<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="keywords" content="Hexo Theme Redefine">
    
    <meta name="author" content="雲之残骸">
    <!-- preconnect -->
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    
    
    <!--- Seo Part-->
    
    <link rel="canonical" href="https://wreckloud.github.io/2023/09/17/cpp11起-新特性/"/>
    <meta name="robots" content="index,follow">
    <meta name="googlebot" content="index,follow">
    <meta name="revisit-after" content="1 days">
    
        <meta name="description" content="关于C++11起的一些新特性介绍.本文由我朋友 @EMCC 所编写">
<meta property="og:type" content="article">
<meta property="og:title" content="C++11起-新特性">
<meta property="og:url" content="https://wreckloud.github.io/2023/09/17/CPP11%E8%B5%B7-%E6%96%B0%E7%89%B9%E6%80%A7/index.html">
<meta property="og:site_name" content="赛博狼窝">
<meta property="og:description" content="关于C++11起的一些新特性介绍.本文由我朋友 @EMCC 所编写">
<meta property="og:locale" content="zh_CN">
<meta property="article:published_time" content="2023-09-17T10:36:50.000Z">
<meta property="article:modified_time" content="2023-09-17T15:10:22.924Z">
<meta property="article:author" content="Wreckloud">
<meta property="article:tag" content="学习笔记">
<meta name="twitter:card" content="summary">
    
    
    <!--- Icon Part-->
    <link rel="icon" type="image/png" href="/images/web.png" sizes="192x192">
    <link rel="apple-touch-icon" sizes="180x180" href="/images/web.png">
    <meta name="theme-color" content="#A31F34">
    <link rel="shortcut icon" href="/images/web.png">
    <!--- Page Info-->
    
    <title>
        
            C++11起-新特性 -
        
        赛博狼窝
    </title>
    
<link rel="stylesheet" href="/css/style.css">


    
        
<link rel="stylesheet" href="/css/build/styles.css">

    

    
<link rel="stylesheet" href="/fonts/fonts.css">

    
<link rel="stylesheet" href="/fonts/Satoshi/satoshi.css">

    
<link rel="stylesheet" href="/fonts/Chillax/chillax.css">

    <!--- Font Part-->
    
    
        <link href="" rel="stylesheet">
    
    
    

    <!--- Inject Part-->
    
    <script id="hexo-configurations">
    let Global = window.Global || {};
    Global.hexo_config = {"hostname":"wreckloud.github.io","root":"/","language":"zh-CN","path":"search.xml"};
    Global.theme_config = {"articles":{"style":{"font_size":"16px","line_height":1.5,"image_border_radius":"4px","image_alignment":"center","image_caption":true,"link_icon":true},"word_count":{"enable":true,"count":true,"min2read":true},"author_label":{"enable":true,"auto":false,"list":[]},"code_block":{"copy":false,"style":"simple","font":{"enable":"ture","family":null,"url":null}},"toc":{"enable":true,"max_depth":3,"number":false,"expand":true,"init_open":true},"copyright":false,"lazyload":true,"recommendation":{"enable":false,"title":"推荐阅读","limit":3,"mobile_limit":2,"placeholder":"/images/wallhaven-wqery6-light.webp","skip_dirs":[]}},"colors":{"primary":"#A31F34","secondary":null},"global":{"fonts":{"chinese":{"enable":false,"family":null,"url":null},"english":{"enable":false,"family":null,"url":null}},"content_max_width":"1000px","sidebar_width":"210px","hover":{"shadow":true,"scale":false},"scroll_progress":{"bar":false,"percentage":true},"website_counter":{"url":"https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js","enable":false,"site_pv":true,"site_uv":true,"post_pv":true},"single_page":true,"open_graph":true,"google_analytics":{"enable":false,"id":null}},"home_banner":{"enable":true,"style":"fixed","image":{"light":"/images/wallhaven-wqery6-light.webp","dark":"/images/wallhaven-wqery6-dark.webp"},"title":"今天也要好心情!","subtitle":{"text":["正在加载..."],"hitokoto":{"enable":"ture","api":"https://v1.hitokoto.cn"},"typing_speed":130,"backing_speed":80,"starting_delay":1500,"backing_delay":3000,"loop":false,"smart_backspace":true},"text_color":{"light":"#fff","dark":"#d1d1b6"},"text_style":{"title_size":"2.8rem","subtitle_size":"1.5rem","line_height":1.2},"custom_font":{"enable":false,"family":null,"url":null},"social_links":{"enable":false,"links":{"github":null,"instagram":null,"zhihu":null,"twitter":null,"bilibili":null},"qrs":{"weixin":null}}},"plugins":{"feed":{"enable":false},"aplayer":{"enable":false,"type":"fixed","audios":[{"name":null,"artist":null,"url":null,"cover":null}]},"mermaid":{"enable":true,"version":"9.3.0"}},"version":"2.4.4","navbar":{"auto_hide":false,"color":{"left":"#f78736","right":"#367df7","transparency":35},"links":{"Home":{"path":"/","icon":"fa-solid fa-house"},"tags":{"path":"/tag/","icon":"fa-solid fa-tags"},"Status":{"path":"/masonry/","icon":"fa-solid fa-sparkles"},"About":{"icon":"fa-solid fa-feather","submenus":{"关于我":"/about/","我的b站":"https://space.bilibili.com/177822535?spm_id_from=333.1007.0.0"}}},"search":{"enable":true,"preload":true}},"page_templates":{"friends_column":2,"tags_style":"blur"},"home":{"sidebar":{"enable":true,"position":"left","first_item":"info","announcement":"欢迎朋友们参观!  不过刚刚搭好现在还没什么内容呢...","links":null},"article_date_format":"auto","categories":{"enable":true,"limit":3},"tags":{"enable":true,"limit":3}},"footerStart":"2023/9/17 14:00:00"};
    Global.language_ago = {"second":"%s 秒前","minute":"%s 分钟前","hour":"%s 小时前","day":"%s 天前","week":"%s 周前","month":"%s 个月前","year":"%s 年前"};
    Global.data_config = {"masonry":true};
  </script>
    
    <!--- Fontawesome Part-->
    
<link rel="stylesheet" href="/fontawesome/fontawesome.min.css">

    
<link rel="stylesheet" href="/fontawesome/brands.min.css">

    
<link rel="stylesheet" href="/fontawesome/solid.min.css">

    
<link rel="stylesheet" href="/fontawesome/regular.min.css">

    
    
    
    
<meta name="generator" content="Hexo 6.3.0"></head>


<body>
<div class="progress-bar-container">
    

    
        <span class="pjax-progress-bar"></span>
        <span class="swup-progress-icon">
            <i class="fa-solid fa-circle-notch fa-spin"></i>
        </span>
    
</div>


<main class="page-container" id="swup">

    

    <div class="main-content-container">


        <div class="main-content-header">
            <header class="navbar-container">
    
    <div class="navbar-content">
        <div class="left">
            
            <a class="logo-title" href="https://wreckloud.github.io/">
                
                赛博狼窝
                
            </a>
        </div>

        <div class="right">
            <!-- PC -->
            <div class="desktop">
                <ul class="navbar-list">
                    
                        
                            <li class="navbar-item">
                                <!-- Menu -->
                                <a class="" 
                                    href="/"  >
                                    
                                        
                                            <i class="fa-solid fa-house"></i>
                                        
                                        首页
                                    
                                </a>
                                <!-- Submenu -->
                                
                            </li>
                    
                        
                            <li class="navbar-item">
                                <!-- Menu -->
                                <a class="" 
                                    href="/tag/"  >
                                    
                                        
                                            <i class="fa-solid fa-tags"></i>
                                        
                                        标签
                                    
                                </a>
                                <!-- Submenu -->
                                
                            </li>
                    
                        
                            <li class="navbar-item">
                                <!-- Menu -->
                                <a class="" 
                                    href="/masonry/"  >
                                    
                                        
                                            <i class="fa-solid fa-sparkles"></i>
                                        
                                        画廊
                                    
                                </a>
                                <!-- Submenu -->
                                
                            </li>
                    
                        
                            <li class="navbar-item">
                                <!-- Menu -->
                                <a class="has-dropdown" 
                                    href="#" onClick="return false;">
                                    
                                        
                                            <i class="fa-solid fa-feather"></i>
                                        
                                        关于&nbsp;<i class="fa-solid fa-chevron-down"></i>
                                    
                                </a>
                                <!-- Submenu -->
                                
                                    <ul class="sub-menu">
                                    
                                        <li>
                                        <a href="/about/">关于我
                                        </a>
                                        </li>
                                    
                                        <li>
                                        <a target="_blank" rel="noopener" href="https://space.bilibili.com/177822535?spm_id_from=333.1007.0.0">我的B站
                                        </a>
                                        </li>
                                    
                                    </ul>
                                
                            </li>
                    
                    
                        <li class="navbar-item search search-popup-trigger">
                            <i class="fa-solid fa-magnifying-glass"></i>
                        </li>
                    
                </ul>
            </div>
            <!-- Mobile -->
            <div class="mobile">
                
                    <div class="icon-item search search-popup-trigger"><i class="fa-solid fa-magnifying-glass"></i></div>
                
                <div class="icon-item navbar-bar">
                    <div class="navbar-bar-middle"></div>
                </div>
            </div>
        </div>
    </div>

    <!-- Mobile drawer -->
    <div class="navbar-drawer w-full absolute top-0 left-0 bg-background-color">
        <ul class="drawer-navbar-list flex flex-col justify-start items-center">
            
                
                    <li class="drawer-navbar-item text-base my-1.5 flex justify-center items-center">
                        <a class="rounded-3xl py-1.5 px-5 hover:border hover:!text-primary active:!text-primary group " 
                        href="/"  >
                             
                                
                                    <i class="fa-solid fa-house"></i>
                                
                                首页
                            
                        </a>
                    </li>
                    <!-- Submenu -->
                    
            
                
                    <li class="drawer-navbar-item text-base my-1.5 flex justify-center items-center">
                        <a class="rounded-3xl py-1.5 px-5 hover:border hover:!text-primary active:!text-primary group " 
                        href="/tag/"  >
                             
                                
                                    <i class="fa-solid fa-tags"></i>
                                
                                标签
                            
                        </a>
                    </li>
                    <!-- Submenu -->
                    
            
                
                    <li class="drawer-navbar-item text-base my-1.5 flex justify-center items-center">
                        <a class="rounded-3xl py-1.5 px-5 hover:border hover:!text-primary active:!text-primary group " 
                        href="/masonry/"  >
                             
                                
                                    <i class="fa-solid fa-sparkles"></i>
                                
                                画廊
                            
                        </a>
                    </li>
                    <!-- Submenu -->
                    
            
                
                    <li class="drawer-navbar-item text-base my-1.5 flex justify-center items-center">
                        <a class="rounded-3xl py-1.5 px-5 hover:border hover:!text-primary active:!text-primary group has-dropdown" 
                        href="#" onClick="return false;">
                            
                                
                                    <i class="fa-solid fa-feather"></i>
                                
                                关于&nbsp;<i class="group-hover:rotate-180 transition-transform fa-solid fa-chevron-down"></i>
                            
                        </a>
                    </li>
                    <!-- Submenu -->
                              
                        
                            <li class="text-base flex justify-center items-center hover:underline active:underline hover:underline-offset-1 rounded-3xl">
                                <a class="py-0.5" href="/about/">关于我</a>
                            </li>
                        
                            <li class="text-base flex justify-center items-center hover:underline active:underline hover:underline-offset-1 rounded-3xl">
                                <a class="py-0.5" target="_blank" rel="noopener" href="https://space.bilibili.com/177822535?spm_id_from=333.1007.0.0">我的B站</a>
                            </li>
                        
                    
            

        </ul>
    </div>

    <div class="window-mask"></div>

</header>


        </div>

        <div class="main-content-body">

            

            <div class="main-content">

                
                    <div class="post-page-container">
    <div class="article-content-container">

        <div class="article-title">
            
                
                
                <img src="/../img/C++11%E5%B0%81%E9%9D%A2.png" alt="C++11起-新特性" class="max-w-none"/>
                
                <h1 class="article-title-cover">C++11起-新特性</h1>
            
            </div>
            
                    
        
        
            <div class="article-header">
                <div class="avatar">
                    <img src="/images/default.png">
                </div>
                <div class="info">
                    <div class="author">
                        <span class="name">雲之残骸</span>
                        
                            <span class="author-label">Lv1</span>
                        
                    </div>
                    <div class="meta-info">
                        <div class="article-meta-info">
    <span class="article-date article-meta-item">
        <i class="fa-regular fa-pen-fancy"></i>&nbsp;
        <span class="desktop">2023-09-17 18:36:50</span>
        <span class="mobile">2023-09-17 18:36:50</span>
        <span class="hover-info">创建</span>
    </span>
    
        <span class="article-date article-meta-item">
            <i class="fa-regular fa-wrench"></i>&nbsp;
            <span class="desktop">2023-09-17 23:10:22</span>
            <span class="mobile">2023-09-17 23:10:22</span>
            <span class="hover-info">更新</span>
        </span>
    

    
    
        <span class="article-tags article-meta-item">
            <i class="fa-regular fa-tags"></i>&nbsp;
            <ul>
                
                    <li>
                        <a href="/tags/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/">学习笔记</a>&nbsp;
                    </li>
                
            </ul>
        </span>
    

    
    
        <span class="article-wordcount article-meta-item">
            <i class="fa-regular fa-typewriter"></i>&nbsp;<span>31.4k 字</span>
        </span>
    
    
        <span class="article-min2read article-meta-item">
            <i class="fa-regular fa-clock"></i>&nbsp;<span>128 分钟</span>
        </span>
    
    
</div>

                    </div>
                </div>
            </div>
        

        


        <div class="article-content markdown-body">
            <p>本文是关于C++11起的一些新特性介绍.由我朋友@EMCC所编写,他的b站:<br><a class="link"   target="_blank" rel="noopener" href="https://space.bilibili.com/1843315943" >EMC方的b站空间 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p>
<h1 id="列表初始化"><a href="#列表初始化" class="headerlink" title="列表初始化"></a>列表初始化</h1><h2 id="初始化赋值"><a href="#初始化赋值" class="headerlink" title="初始化赋值"></a>初始化赋值</h2><p><code>C++11</code>允许普通变量和数组也使用列表初始化赋值。</p>
<p>旧标准：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> a = <span class="number">15</span>;		<span class="comment">//声明变量a，初始值为15</span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">b</span><span class="params">(<span class="number">15</span>)</span></span>;		<span class="comment">//声明变量b，初始值为15</span></span><br><span class="line"><span class="type">int</span> arr[]=&#123; <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>&#125;;<span class="comment">//声明数组arr，3个元素1、2、3</span></span><br></pre></td></tr></table></figure></div>

<p><code>C++11</code>标准，（统一初始化列表，赋值等号可省略）：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> a = &#123;<span class="number">15</span>&#125;;			<span class="comment">//声明变量a，初始值为15</span></span><br><span class="line"><span class="type">int</span> b&#123;<span class="number">15</span>&#125;;				<span class="comment">//声明变量b，初始值为15</span></span><br><span class="line"><span class="type">int</span> arr[]&#123; <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>&#125;;	<span class="comment">//声明变量b，初始值为15</span></span><br></pre></td></tr></table></figure></div>

<h2 id="列表初始化防止类型收窄"><a href="#列表初始化防止类型收窄" class="headerlink" title="列表初始化防止类型收窄"></a>列表初始化防止类型收窄</h2><p>类型收窄是指，变量赋值时发生隐式类型转换，因为数据精度或范围不匹配，导致精度丢失或数据丢失。</p>
<p>示例：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> a = <span class="number">1024</span>;</span><br><span class="line">	<span class="type">char</span> b = a; <span class="comment">//编译不会报错，但数据丢失,类型收窄</span></span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;b = %din&quot;</span>, b);<span class="comment">//输出结果为0</span></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>使用列表初始化可以防止上面的类型收窄。</p>
<p>示例：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> a = <span class="number">1024</span>;</span><br><span class="line">    <span class="type">char</span> b&#123; a &#125;;<span class="comment">//编译时会直接报错，提示：C2397 从&quot;int&quot;转换到&quot; char&quot;需要收缩转换</span></span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;b = %din&quot;</span>, b);</span><br><span class="line">	<span class="built_in">system</span>(<span class="string">&quot;pause&gt;nul&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>注意！部分编译器会运行编译通过，但可能会有警告提示或者没有任何提示，但打印<code>b</code>的值时，仍然为<code>0</code>。</p>
<h1 id="原始字面量"><a href="#原始字面量" class="headerlink" title="原始字面量"></a>原始字面量</h1><p>在 <code>C++11</code>中添加了定义原始字符串的字面量。</p>
<p>语法：</p>
<ul>
<li><code>R “xxx(原始字符串)xxx”</code></li>
<li>其中<code>()</code>两边的字符串是说明文字，类似注释，可以省略。</li>
<li><code>()</code>两边的字符必须一样，否则编译不通过。</li>
</ul>
<p>原始字面量<code>R</code>可以直接表示字符串的实际含义，而不需要额外对字符串做转译或连接等操作。</p>
<p>原始字面量<code>R</code>可以直接赋值给<code>string</code>字符串，内容完全与原始字面量内的内容相同。</p>
<p>示例：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;string&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    string str = <span class="string">&quot;D:\hello\world\test.text&quot;</span>;</span><br><span class="line">    cout &lt;&lt; str &lt;&lt; endl;</span><br><span class="line">    string str1 = <span class="string">&quot;D:\\hello\\world\\test.text&quot;</span>;</span><br><span class="line">    cout &lt;&lt; str1 &lt;&lt; endl;</span><br><span class="line">    string str2 = <span class="string">R&quot;(D:\hello\world\test.text)&quot;</span>;</span><br><span class="line">    cout &lt;&lt; str2 &lt;&lt; endl;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>输出结果：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">D:helloworld    est.text</span><br><span class="line">D:\hello\world\test.text</span><br><span class="line">D:\hello\world\test.text</span><br></pre></td></tr></table></figure></div>

<p>在<code>C++11</code>之前如果一个字符串分别写到了不同的行里边，需要加连接符，这种方式不仅繁琐，还破坏了表达式的原始含义，如果使用原始字面量就变得简单很多，很强直观，可读性强。</p>
<p>示例：</p>
<ul>
<li><p>非<code>C++11</code>：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;string&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    string str = <span class="string">&quot;&lt;html&gt;\</span></span><br><span class="line"><span class="string">        &lt;head&gt;\</span></span><br><span class="line"><span class="string">        &lt;title&gt;\</span></span><br><span class="line"><span class="string">        海贼王\</span></span><br><span class="line"><span class="string">        &lt;/title&gt;\</span></span><br><span class="line"><span class="string">        &lt;/head&gt;\</span></span><br><span class="line"><span class="string">        &lt;body&gt;\</span></span><br><span class="line"><span class="string">        &lt;p&gt;\</span></span><br><span class="line"><span class="string">        我是要成为海贼王的男人!!!\</span></span><br><span class="line"><span class="string">        &lt;/p&gt;\</span></span><br><span class="line"><span class="string">        &lt;/body&gt;\</span></span><br><span class="line"><span class="string">        &lt;/html&gt;&quot;</span>;</span><br><span class="line">    cout &lt;&lt; str &lt;&lt; endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>
</li>
<li><p><code>C++11</code></p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;string&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    string str = <span class="string">R&quot;(&lt;html&gt;</span></span><br><span class="line"><span class="string">        &lt;head&gt;</span></span><br><span class="line"><span class="string">        &lt;title&gt;</span></span><br><span class="line"><span class="string">        海贼王</span></span><br><span class="line"><span class="string">        &lt;/title&gt;</span></span><br><span class="line"><span class="string">        &lt;/head&gt;</span></span><br><span class="line"><span class="string">        &lt;body&gt;</span></span><br><span class="line"><span class="string">        &lt;p&gt;</span></span><br><span class="line"><span class="string">        我是要成为海贼王的男人!!!</span></span><br><span class="line"><span class="string">        &lt;/p&gt;</span></span><br><span class="line"><span class="string">        &lt;/body&gt;</span></span><br><span class="line"><span class="string">        &lt;/html&gt;)&quot;</span>;</span><br><span class="line">    cout &lt;&lt; str &lt;&lt; endl;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div></li>
</ul>
<h1 id="自动类型推导"><a href="#自动类型推导" class="headerlink" title="自动类型推导"></a>自动类型推导</h1><h2 id="auto自动类型推导"><a href="#auto自动类型推导" class="headerlink" title="auto自动类型推导"></a><code>auto</code>自动类型推导</h2><hr>
<h3 id="使用示例"><a href="#使用示例" class="headerlink" title="使用示例"></a>使用示例</h3><hr>
<p><code>auto</code>的自动类型推导，用于从初始化表达式中推断出变量的数据类型。</p>
<p>从这个意义上讲，<code>auto</code>并非一种类型声明，而是一个类型声明时的占位符，编译器在编译时期会将<code>auto</code>替换为变量实际的类型。</p>
<p>通过<code>auto</code>的自动类型推导，可以大大简化我们的编程工作。</p>
<p>示例（<code>auto</code>配合模板使用）：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">func</span><span class="params">(vector&lt;<span class="type">int</span>&gt; &amp;tmp)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="keyword">for</span> (<span class="keyword">auto</span> i= tmp.<span class="built_in">begin</span>(); i != tmp.<span class="built_in">end</span>();++i)</span><br><span class="line">    &#123;</span><br><span class="line">		cout &lt;&lt; *i;</span><br><span class="line">    &#125;</span><br><span class="line">    cout &lt;&lt; endl;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>上面的代码中无需明确指定<code>i</code>的类型，使用<code>auto</code>后编译器会自动推导<code>i</code>的类型，极大方便了代码编写。</p>
<h3 id="推导规则"><a href="#推导规则" class="headerlink" title="推导规则"></a>推导规则</h3><hr>
<p><code>auto</code>可以和引用、指针一起结合使用，还可以带上<code>const</code>和<code>volatile</code>修饰符。</p>
<p>通过一组例子来理解一下推导规则：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> x = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">auto</span> * a = &amp;x; 			<span class="comment">//a→int *，auto被推导为int</span></span><br><span class="line"><span class="keyword">auto</span> b = x; 			<span class="comment">//b→int，auto被推导为int</span></span><br><span class="line"><span class="keyword">auto</span> c = &amp;x; 			<span class="comment">//c→int &amp;,atuo被推导为int</span></span><br><span class="line"><span class="keyword">auto</span> *d = x; 			<span class="comment">//error，无法推导auto类型，因为指针未被限定为常量</span></span><br><span class="line"><span class="keyword">auto</span> &amp;e = x; 			<span class="comment">//e→const int&amp;,auto被推导为 int</span></span><br><span class="line"><span class="keyword">auto</span> &amp;f = &amp;x; 			<span class="comment">// error, 未定义const int地址指向的内容</span></span><br><span class="line"><span class="type">const</span> <span class="keyword">auto</span> g = x; 		<span class="comment">//g→const int,auto被推导为int</span></span><br><span class="line"><span class="type">const</span> <span class="keyword">auto</span> *h = x; 		<span class="comment">//error，指针类型未定义</span></span><br><span class="line"><span class="type">const</span> <span class="keyword">auto</span> &amp;i = x; 		<span class="comment">//i→ const int，auto被推导为int</span></span><br><span class="line"><span class="type">const</span> <span class="keyword">auto</span> j = &amp;x; 		<span class="comment">//j→const int *,auto被推导为int</span></span><br><span class="line"><span class="type">const</span> <span class="keyword">auto</span> *k = &amp;x; 	<span class="comment">//k→const int *,auto被推导为int</span></span><br><span class="line">   <span class="type">const</span> <span class="keyword">auto</span> &amp;l = &amp;x; 	<span class="comment">//l→const int *，auto被推导为int，这里和未加const限定符的区别是，const限定了指针为常量</span></span><br></pre></td></tr></table></figure></div>

<h3 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h3><hr>
<ul>
<li><p>使用<code>auto</code>定义的变量必须初始化。</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> a=<span class="number">10</span>;</span><br><span class="line">    <span class="keyword">auto</span> b ;<span class="comment">//编译报错，auto定义的变量必须初始化。</span></span><br><span class="line">    b = <span class="number">20</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>
</li>
<li><p>低版本编译器中，函数的参数列表不支持<code>auto</code>变量。</p>
<p>示例：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//VS2013，不支持以下写法，但高版本编译器支持</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">fun</span><span class="params">(<span class="keyword">auto</span> a)</span></span>&#123;<span class="comment">//编译报错</span></span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>
</li>
<li><p><code>auto</code>变量不能作为自定义类型的成员变量。</p>
<p>示例：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">  <span class="keyword">struct</span> <span class="title class_">ak</span></span><br><span class="line">  &#123;</span><br><span class="line">  	<span class="type">int</span> a;</span><br><span class="line">  	<span class="keyword">auto</span> b = <span class="number">90</span>;<span class="comment">//编译报错，此处不允许使用auto</span></span><br><span class="line">  &#125;;</span><br><span class="line"></span><br><span class="line">- `<span class="keyword">auto</span>`不能用于定义数组。</span><br><span class="line"></span><br><span class="line">  示例：</span><br><span class="line"></span><br><span class="line">  ```c++</span><br><span class="line">  <span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function">  </span>&#123;</span><br><span class="line">  	<span class="keyword">auto</span> sd[] = &#123;<span class="number">0</span>,<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>&#125;;<span class="comment">//编译报错，auto类型不能出现在顶级数组类型中</span></span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure></div>
</li>
<li><p>模板实例化参数不能是<code>auto</code>。</p>
<p>示例：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vector&lt;<span class="keyword">auto</span>&gt;b = &#123; <span class="number">1</span> &#125;;<span class="comment">//编译报错，此处不允许使用auto</span></span><br></pre></td></tr></table></figure></div>
</li>
<li><p><code>auto</code>只能用于类的静态成员，不能用于类的非静态成员（普通成员），如果我们想推导非静态成员的类型，这个时候就必须使用<code>decltype</code>了。</p>
</li>
</ul>
<h2 id="decltype自动类型推导"><a href="#decltype自动类型推导" class="headerlink" title="decltype自动类型推导"></a><code>decltype</code>自动类型推导</h2><hr>
<h3 id="使用示例-1"><a href="#使用示例-1" class="headerlink" title="使用示例"></a>使用示例</h3><hr>
<p><code>decltype</code>实际上有点像<code>auto</code>的反函数，<code>auto</code>可以让你声明一个变量，而<code>decltype</code>则可以从一个变量或表达式中得到其类型。</p>
<p>因为<code>auto</code>并不适用于所有的自动类型推导场景，在某些特殊情况下<code>auto</code>用起来非常不方便，甚至压根无法使用，所以<code>decltype</code>关键字也被引入到<code>C++11</code>中。</p>
<p>使用示例：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="type">int</span> i;</span><br><span class="line">	<span class="keyword">decltype</span>(i) j = <span class="number">0</span>;</span><br><span class="line">	cout &lt;&lt; <span class="built_in">typeid</span>(j).<span class="built_in">name</span>() &lt;&lt; endl;</span><br><span class="line">    </span><br><span class="line">	<span class="type">float</span> a;</span><br><span class="line">	<span class="type">double</span> b;</span><br><span class="line">	<span class="keyword">decltype</span>(a + b) c;</span><br><span class="line">	cout &lt;&lt; <span class="built_in">typeid</span>(c).<span class="built_in">name</span>() &lt;&lt;endl;</span><br><span class="line">    </span><br><span class="line">	vector&lt;<span class="type">int</span>&gt; tmp;</span><br><span class="line">	<span class="keyword">decltype</span>(tmp.<span class="built_in">begin</span>()) k;</span><br><span class="line">	<span class="keyword">for</span> (k = tmp.<span class="built_in">begin</span>(); k != tmp.<span class="built_in">end</span>();++k)</span><br><span class="line">    &#123;</span><br><span class="line">		<span class="comment">//......</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>输出结果：</p>
<div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">int</span><br><span class="line">double</span><br><span class="line">class std::_Vector_iterator&lt;class std::_Vector_val&lt;struct std::_Simple_types&lt;int&gt; &gt; &gt;</span><br></pre></td></tr></table></figure></div>

<p>对于匿名类型的变量，可以通过<code>decltype</code>获取类型后再次定义变量。</p>
<p>示例：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">enum</span> &#123;Ok, Error &#125; flag;<span class="comment">//匿名类型的枚举变量flag，在C++11以前，后续代码中无法再次定义这个枚举变量</span></span><br><span class="line"><span class="keyword">decltype</span>(flag) flag2;<span class="comment">//通过decltype获取flag的类型，再次定义这个匿名枚举类型的变量flag2</span></span><br></pre></td></tr></table></figure></div>

<h3 id="推导规则-1"><a href="#推导规则-1" class="headerlink" title="推导规则"></a>推导规则</h3><hr>
<p>当程使用<code>decltype(exp)</code>获取类型时，编译器将根据以下三条规则得出结果：</p>
<ul>
<li>如果<code>exp</code>是一个不被括号<code>()</code>包围的表达式，或者是一个类成员访问表达式，或者是一个单独的变量，那么<code>decltype(exp)</code>的类型就和<code>exp</code>一致。</li>
<li>如果<code>exp</code>是函数调用，那么<code>decltype(exp)</code>的类型就和函数返回值的类型一致。</li>
<li>如果<code>exp</code> 是一个左值，或者被括号<code>()</code>包围，那么<code>decltype(exp)</code>的类型就是<code>exp</code>的引用；假设<code>exp</code>的类型为<code>T</code>，那么<code>decltype(exp)</code>的类型就是<code>T&amp;</code></li>
</ul>
<p>几个实际的例子：</p>
<ul>
<li><p>示例1：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Student</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="type">static</span> <span class="type">int</span> total;</span><br><span class="line">    string name;</span><br><span class="line">    <span class="type">int</span> age;</span><br><span class="line">    <span class="type">float</span> scores;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="type">int</span> Student::total = <span class="number">0</span>;</span><br><span class="line"><span class="function"><span class="type">int</span>  <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> n = <span class="number">0</span>;</span><br><span class="line">    <span class="type">const</span> <span class="type">int</span> &amp;r = n;</span><br><span class="line">    Student stu;</span><br><span class="line">    <span class="keyword">decltype</span>(n) a = n;  	<span class="comment">//n 为 int 类型，a 被推导为 int 类型</span></span><br><span class="line">    <span class="keyword">decltype</span>(r) b = n;     	<span class="comment">//r 为 const int&amp; 类型, b 被推导为 const int&amp; 类型</span></span><br><span class="line">    <span class="keyword">decltype</span>(Student::total) c = <span class="number">0</span>;  <span class="comment">//total 为类 Student 的一个 int 类型的成员变量，c 被推导为 int 类型</span></span><br><span class="line">    <span class="keyword">decltype</span>(stu.name) url = <span class="string">&quot;http://c.biancheng.net/cplus/&quot;</span>;  <span class="comment">//total 为类 Student 的一个 string 类型的成员变量，url被推导为 string 类型</span></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>
</li>
<li><p>示例2：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*-------------函数声明--------------*/</span></span><br><span class="line"><span class="function"><span class="type">int</span>&amp; <span class="title">func_int_r</span><span class="params">(<span class="type">int</span>, <span class="type">char</span>)</span></span>;				<span class="comment">//返回值为 int&amp;</span></span><br><span class="line"><span class="function"><span class="type">int</span>&amp;&amp; <span class="title">func_int_rr</span><span class="params">(<span class="type">void</span>)</span></span>;				<span class="comment">//返回值为 int&amp;&amp;</span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">func_int</span><span class="params">(<span class="type">double</span>)</span></span>;					<span class="comment">//返回值为 int</span></span><br><span class="line"><span class="function"><span class="type">const</span> <span class="type">int</span>&amp; <span class="title">fun_cint_r</span><span class="params">(<span class="type">int</span>, <span class="type">int</span>, <span class="type">int</span>)</span></span>;	<span class="comment">//返回值为 const int&amp;</span></span><br><span class="line"><span class="function"><span class="type">const</span> <span class="type">int</span>&amp;&amp; <span class="title">func_cint_rr</span><span class="params">(<span class="type">void</span>)</span></span>;			<span class="comment">//返回值为 const int&amp;&amp;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/*-------------decltype类型推导---------*/</span></span><br><span class="line"><span class="type">int</span> n = <span class="number">100</span>;</span><br><span class="line"><span class="keyword">decltype</span>(<span class="built_in">func_int_r</span>(<span class="number">100</span>, <span class="string">&#x27;A&#x27;</span>)) a = n;  	<span class="comment">//a 的类型为 int&amp;</span></span><br><span class="line"><span class="keyword">decltype</span>(<span class="built_in">func_int_rr</span>()) b = <span class="number">0</span>;  		<span class="comment">//b 的类型为 int&amp;&amp;</span></span><br><span class="line"><span class="keyword">decltype</span>(<span class="built_in">func_int</span>(<span class="number">10.5</span>)) c = <span class="number">0</span>;   		<span class="comment">//c 的类型为 int</span></span><br><span class="line"><span class="keyword">decltype</span>(<span class="built_in">fun_cint_r</span>(<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>))  x = n;    	<span class="comment">//x 的类型为 const int &amp;</span></span><br><span class="line"><span class="keyword">decltype</span>(<span class="built_in">func_cint_rr</span>()) y = <span class="number">0</span>;  		<span class="comment">// y 的类型为 const int&amp;&amp;</span></span><br></pre></td></tr></table></figure></div>
</li>
<li><p>示例3：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Base</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="type">int</span> x;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">const</span> Base obj;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//带有括号的表达式</span></span><br><span class="line">    <span class="keyword">decltype</span>(obj.x) a = <span class="number">0</span>;  	<span class="comment">//obj.x 为类的成员访问表达式，符合推导规则一，a 的类型为 int</span></span><br><span class="line">    <span class="keyword">decltype</span>((obj.x)) b = a;  	<span class="comment">//obj.x 带有括号，符合推导规则三，b 的类型为 int&amp;。</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">//加法表达式</span></span><br><span class="line">    <span class="type">int</span> n = <span class="number">0</span>, m = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">decltype</span>(n + m) c = <span class="number">0</span>;  	<span class="comment">//n+m 得到一个右值，符合推导规则一，所以推导结果为 int</span></span><br><span class="line">    <span class="keyword">decltype</span>(n = n + m) d = c;  <span class="comment">//n=n+m 得到一个左值，符号推导规则三，所以推导结果为 int&amp;</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div></li>
</ul>
<h2 id="追踪返回类型"><a href="#追踪返回类型" class="headerlink" title="追踪返回类型"></a>追踪返回类型</h2><hr>
<h3 id="普通函数"><a href="#普通函数" class="headerlink" title="普通函数"></a>普通函数</h3><hr>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">func1</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> a+ b;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">auto</span> <span class="title">func2</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b)</span> -&gt; <span class="type">int</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> a + b;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">auto</span> <span class="title">func3</span><span class="params">(<span class="type">int</span> a, <span class="type">double</span> b)</span> -&gt; <span class="title">decltype</span><span class="params">(a+b)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> a+ b;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">auto</span> <span class="title">func4</span><span class="params">(<span class="keyword">auto</span> a, <span class="keyword">auto</span> b)</span> -&gt; <span class="title">decltype</span><span class="params">(a + b)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="keyword">return</span> a + b;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>对于上面3个函数，<code>func1</code>是传统写法，指定返回值类型，返回值始终是<code>int</code>；</p>
<p><code>func2</code>使用<code>auto</code>推导返回值类型，但在参数列表后面指定了<code>auto</code>的类型为<code>int</code>；</p>
<p><code>func3</code>使用<code>auto</code>推导返回值类型，并在参数列表后指定<code>auto</code>的类型为使用<code>decltype</code>推导出的结果。（返回值类型应该仍然为<code>double</code>，因为<code>int+double</code>发生隐式类型转换，类型仍应该为<code>double</code>。）</p>
<p>但对于<code>func4</code>，使用<code>auto</code>推导传入的参数，同时推导返回值类型，并指定<code>auto</code>的类型为使用<code>decltype</code>推导出的结果，这样子写更加智能和方便，无需明确指定返回值类型，避免了重载减少了重复代码。</p>
<p>示例：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">auto</span> <span class="title">func</span><span class="params">(<span class="keyword">auto</span> a, <span class="keyword">auto</span> b)</span> -&gt; <span class="title">decltype</span><span class="params">(a + b)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="keyword">return</span> a + b;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="keyword">auto</span> a = <span class="built_in">func</span>(<span class="number">10</span>,<span class="number">90</span>);</span><br><span class="line">	cout &lt;&lt; <span class="built_in">typeid</span>(a).<span class="built_in">name</span>() &lt;&lt; endl;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">auto</span> b = <span class="built_in">func</span>(<span class="number">0.5</span>,<span class="number">10</span>);</span><br><span class="line">	cout &lt;&lt; <span class="built_in">typeid</span>(b).<span class="built_in">name</span>() &lt;&lt; endl;</span><br><span class="line"></span><br><span class="line">	<span class="type">float</span> m= <span class="number">0.123456789</span>;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">auto</span> c = <span class="built_in">func</span>(m, <span class="number">10</span>);</span><br><span class="line">	cout &lt;&lt; <span class="built_in">typeid</span>(c).<span class="built_in">name</span>() &lt;&lt; endl;</span><br><span class="line"></span><br><span class="line">	<span class="built_in">system</span>(<span class="string">&quot;pause&gt;nul&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>输出结果：</p>
<div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">int</span><br><span class="line">double</span><br><span class="line">float</span><br></pre></td></tr></table></figure></div>

<h3 id="模板函数"><a href="#模板函数" class="headerlink" title="模板函数"></a>模板函数</h3><hr>
<p>对于模板函数，再无法准确判定返回值类型的情况下，也可以使用<code>auto</code>和<code>decltype</code>使编写代码更加方便和和智能。</p>
<p>示例：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">template</span>&lt;<span class="keyword">class</span> T1, <span class="keyword">class</span> T2&gt;</span></span><br><span class="line"><span class="function"><span class="keyword">auto</span> <span class="title">func</span><span class="params">(T1 <span class="type">const</span>&amp; t1, <span class="type">const</span> T2&amp; t2)</span> -&gt; <span class="title">decltype</span><span class="params">(t1* t2)</span><span class="comment">//右值引用，使用const修饰，前后两个位置都可以</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="keyword">return</span> t1 * t2;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="keyword">auto</span> a= <span class="built_in">func</span>(<span class="number">10</span>,<span class="number">10</span>);</span><br><span class="line">	cout &lt;&lt; <span class="string">&quot;a=&quot;</span> &lt;&lt; a &lt;&lt; endl;</span><br><span class="line">	cout &lt;&lt; <span class="built_in">typeid</span>(a).<span class="built_in">name</span>() &lt;&lt; endl;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">auto</span> b = <span class="built_in">func</span>(<span class="number">0.56</span>, <span class="number">10</span>);</span><br><span class="line">	cout &lt;&lt; <span class="string">&quot;b=&quot;</span> &lt;&lt; b &lt;&lt; endl;</span><br><span class="line">	cout &lt;&lt; <span class="built_in">typeid</span>(b).<span class="built_in">name</span>() &lt;&lt; endl;</span><br><span class="line"></span><br><span class="line">	<span class="built_in">system</span>(<span class="string">&quot;pause&gt;nul&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>这里对于模板函数的传入参数无法准确判断其相乘后的返回值类型，因此使用<code>auto</code>和<code>decltype</code>来自动推导返回值。</p>
<p>在上面的例子中也可以省略参数列表后面的 <code>-&gt; decltype(t1* t2)</code>。</p>
<p>输出结果：</p>
<div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">a=100</span><br><span class="line">int</span><br><span class="line">b=5.6</span><br><span class="line">double</span><br></pre></td></tr></table></figure></div>

<h3 id="其他示例"><a href="#其他示例" class="headerlink" title="其他示例"></a>其他示例</h3><hr>
<p>追踪返回类型声明的函数也会带给大家一些喜出望外的效果：</p>
<p>示例：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">OuterType</span></span><br><span class="line"> &#123;</span><br><span class="line">     <span class="keyword">struct</span> <span class="title class_">InnerType</span> &#123; <span class="type">int</span> i; &#125;;</span><br><span class="line">     <span class="function">InnerType <span class="title">GetInner</span><span class="params">()</span></span>;</span><br><span class="line">     InnerType it;</span><br><span class="line"> &#125;;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">auto</span> <span class="title">OuterType::GetInner</span><span class="params">()</span>-&gt;InnerType		 <span class="comment">// 可以不写OuterType::InnerType</span></span></span><br><span class="line"><span class="function"> </span>&#123;</span><br><span class="line">     <span class="keyword">return</span> it;</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure></div>

<p>简化函数的定义。常见于函数指针中。</p>
<p>示例：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;type_traits&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"> <span class="built_in">int</span> (*(*<span class="built_in">pf</span>()) ()) ()</span><br><span class="line"> &#123;</span><br><span class="line">     <span class="keyword">return</span> <span class="literal">nullptr</span>;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 一个返回函数指针的函数（假设为func函数）</span></span><br><span class="line"> <span class="comment">// auto (*)()-&gt;int(*)();</span></span><br><span class="line"> <span class="comment">// 一个返回func函数的指针的函数</span></span><br><span class="line"> <span class="comment">// auto pf1()-&gt;auto (*)() -&gt; int(*)();</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">auto</span> <span class="title">pf1</span><span class="params">()</span> -&gt; <span class="title">auto</span><span class="params">(*)</span><span class="params">()</span> -&gt; <span class="title">int</span> <span class="params">(*)</span><span class="params">()</span></span></span><br><span class="line"><span class="function"> </span>&#123;</span><br><span class="line">     <span class="keyword">return</span> <span class="literal">nullptr</span>;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"> </span>&#123;</span><br><span class="line">     cout &lt;&lt; is_same&lt;<span class="keyword">decltype</span>(pf), <span class="keyword">decltype</span>(pf1)&gt;::value &lt;&lt; endl;  <span class="comment">// 1</span></span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure></div>

<p>广泛应用在转发函数中。</p>
<p>示例：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">double</span> <span class="title">foo</span><span class="params">(<span class="type">int</span> a)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> (<span class="type">double</span>)a + <span class="number">0.1</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">foo</span><span class="params">(<span class="type">double</span> b)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> (<span class="type">int</span>)b;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">class</span> <span class="title class_">T</span>&gt;</span><br><span class="line"><span class="function"><span class="keyword">auto</span> <span class="title">Forward</span><span class="params">(T t)</span> -&gt; <span class="title">decltype</span><span class="params">(foo(t))</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">foo</span>(t);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    cout &lt;&lt; <span class="built_in">Forward</span>(<span class="number">2</span>) &lt;&lt; endl;    <span class="comment">// 2.1</span></span><br><span class="line">    cout &lt;&lt; <span class="built_in">Forward</span>(<span class="number">0.5</span>) &lt;&lt; endl;  <span class="comment">// 0</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>参考链接：<a class="link"   target="_blank" rel="noopener" href="https://blog.csdn.net/qq_45254369/article/details/127452583" > C++11之追踪返回类型_追踪返回值类型_林夕07的博客-CSDN博客 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p>
<h1 id="范围for循环"><a href="#范围for循环" class="headerlink" title="范围for循环"></a>范围<code>for</code>循环</h1><p>传统<code>for</code>循环：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> a[]= &#123; <span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>&#125;;</span><br><span class="line">    <span class="type">int</span> n = <span class="built_in">sizeof</span>(a) / <span class="built_in">sizeof</span>(*a);</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i= <span class="number">0</span>; i&lt;n; ++i)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="type">int</span> tmp = a[i];</span><br><span class="line">        cout &lt;&lt; tmp&lt;&lt; <span class="string">&quot;, &quot;</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	cout &lt;&lt; endl;</span><br><span class="line">	</span><br><span class="line">	<span class="built_in">system</span>(<span class="string">&quot;pause&quot;</span>);<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>C++11范围<code>for</code>循环：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> a[]= &#123; <span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>&#125;;</span><br><span class="line">    </span><br><span class="line">	<span class="keyword">for</span> (<span class="type">int</span> tmp : a)</span><br><span class="line">    &#123;</span><br><span class="line">        cout &lt;&lt; tmp &lt;&lt; <span class="string">&quot;,&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    cout &lt;&lt;endl;</span><br><span class="line">    </span><br><span class="line">	<span class="built_in">system</span>(<span class="string">&quot;pause&quot;</span>);<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>上面两中方式的输出效果是一样的。</p>
<p>同时，范围<code>for</code>循环可以使用引用接受参数，达到修改的目的：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> a[]= &#123; <span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>&#125;;</span><br><span class="line">    </span><br><span class="line">	<span class="keyword">for</span> (<span class="type">int</span>&amp; tmp : a)</span><br><span class="line">    &#123;</span><br><span class="line">        tmp++;<span class="comment">//数组每个值都加1</span></span><br><span class="line">    &#125;</span><br><span class="line">    cout &lt;&lt;endl;</span><br><span class="line">    </span><br><span class="line">	<span class="built_in">system</span>(<span class="string">&quot;pause&quot;</span>);<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>注意！遍历对象必须是确定范围的，如果将一个数组作为参数传入一个函数，那么在函数体中是无法使用范围<code>for</code>循环遍历的，因为数组传入的是首地址，范围大小是不确定的。</p>
<p>范围<code>for</code>循环适用多种容器，包括<code>STL</code>中的大部分容器，使用范围<code>for</code>循环的代码更加简洁明了，可读性更高，使用起来也比传统<code>for</code>循环简单很多。</p>
<h1 id="静态断言"><a href="#静态断言" class="headerlink" title="静态断言"></a>静态断言</h1><p><code>C++</code>提供了调试工具<code>assert()</code>，这是一个宏，用于在&#x3D;&#x3D;运行阶段&#x3D;&#x3D;对断言进行检查，如果条件为真，执行程序，否则调用<code>abort()</code>使程序中断。</p>
<p><code>C++11</code>新增了关键字<code>static_assert</code>，可用于在&#x3D;&#x3D;编译阶段&#x3D;&#x3D;对断言进行测试。</p>
<p>语法：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">static_assert</span>(bool_constexpr,<span class="string">&quot;message&quot;</span>);</span><br><span class="line"><span class="comment">//bool_constexpr必须是常量表达式条件</span></span><br><span class="line"><span class="comment">//message是发生断言时提示的错误信息，只能是双引号包含的字符串文本</span></span><br></pre></td></tr></table></figure></div>

<ul>
<li>静态断言在编译时进行，断言在运行时进行。</li>
<li>因为在编译时不产生目标代码，所以静态断言基本不影响程序运行性能。</li>
<li>静态断言只能在32位机器上进行。</li>
<li>当<code>bool_constexpr</code>为假时，输出错误信息。</li>
<li>静态断言判断表达式涉及模板时，会等待模板实例化后再做判断。</li>
</ul>
<p>静态断言的好处：</p>
<ul>
<li>更早的报告错误，我们知道构建是早于运行的，更早的错误报告意味着开发成本的降低</li>
<li>减少运行时开销，静态断言是编译期检测的，减少了运行时开销</li>
</ul>
<h1 id="使用nullptr取代NULL"><a href="#使用nullptr取代NULL" class="headerlink" title="使用nullptr取代NULL"></a>使用<code>nullptr</code>取代<code>NULL</code></h1><p>在某些情况下<code>int</code> 类型和<code>NULL</code>会产生二义性，因为实际上<code>NULL</code>等于<code>0</code>，大多数情况下编译器会将之看作整形，<code>NULL</code>只是是一个<code>#define NULL 0</code>的宏定义，可以同时赋值给指针和普通变量。当<code>NULL</code>作为参数给函数传参时，编译器会理解成<code>int</code>类型。</p>
<p>为了避免这种二义性的产生，在给指针置空时，更推荐使用<code>nullptr</code>。</p>
<p><code>nullptr</code>是专门用于给指针置空的关键字，尽管表达式：<code>NULL==nullptr</code>的结果为真，但<code>nullptr</code>只能给指针赋值。</p>
<p>总之，在给指针置空时，推荐使用<code>nullptr</code>而不是<code>NULL</code>。</p>
<h1 id="强类型枚举"><a href="#强类型枚举" class="headerlink" title="强类型枚举"></a>强类型枚举</h1><h2 id="传统枚举的局限性"><a href="#传统枚举的局限性" class="headerlink" title="传统枚举的局限性"></a>传统枚举的局限性</h2><hr>
<ul>
<li><p>传统枚举方式枚举成员的作用域在同一作用域下是共享的，无法同时定义两个含有相同名称的枚举成员。</p>
<p>以下情况会报错：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">enum</span> <span class="title class_">Status1</span> &#123;Ok, Error&#125;;</span><br><span class="line">    <span class="keyword">enum</span> <span class="title class_">Status2</span> &#123;Ok, Error&#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>上述代码编译会报错，因为在<code>main</code>函数作用域下，传统枚举成员的作用域是共享的，会发生重定义错误。</p>
<p>当然可以通过多种方式解决这个问题，但会让代码变得繁琐和冗余，可读性下降。</p>
</li>
<li><p>传统枚举不能指定枚举成员类型，默认指定为<code>int</code>整形，因此在作为参数传参等场景下会发生隐式类型转换，导致精度丢失、数据丢失等问题。</p>
</li>
</ul>
<p>详见：<a class="link"   target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV19T411T71n?vd_source=03da7de0e80f9ff60fdeca7b512ba3f5" >C++ 你所不知道的枚举类型（ENUM） <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p>
<h2 id="C-11强类型枚举"><a href="#C-11强类型枚举" class="headerlink" title="C++11强类型枚举"></a><code>C++11</code>强类型枚举</h2><hr>
<p>为了解决上述问题，C++11引入了强类型枚举，解决了枚举成员作用域共享和枚举成员类型不能指定的问题。</p>
<p>语法：</p>
<ul>
<li><p>在<code>enum</code>和枚举名称之间加上<code>class</code>或<code>struct</code>修饰，这两种修饰方式无区别。</p>
</li>
<li><p>在枚举名称后加上“<code>:</code>”和数据类型，可以指定该枚举的枚举成员为冒号后的数据类型。</p>
</li>
<li><p>若不指定枚举成员的数据类型，则仍然默认为<code>int</code>类型。</p>
</li>
<li><p>如果不对枚举成员赋初始值，则按传统枚举默认赋值的规则给枚举成员进行赋值。</p>
</li>
<li><p>指定的枚举成员类型其基础类型必须是整形。如：<code>char</code>、<code>long</code>、<code>long long</code>、<code>unsigned int</code>等。但<code>float</code>、<code>double</code>就不可以，因为其基础类型为浮点型。</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">enum class</span> <span class="title class_">Status</span> &#123; Ok=<span class="number">1</span>, Error &#125;;<span class="comment">//默认 int 类型，默认值：Ok=1、Error=2（Ok+1）</span></span><br><span class="line"><span class="keyword">enum struct</span> <span class="title class_">Status2</span> &#123; Ok=<span class="number">1</span>, Error=<span class="number">9</span>, No&#125;;<span class="comment">//默认 int 类型，并赋值O k=1、Error=9，No没有赋值，则No=10（Error+1）</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">enum struct</span> <span class="title class_">Status3</span> : <span class="type">char</span> &#123; Ok, Error=<span class="string">&#x27;a&#x27;</span>, No&#125;;</span><br><span class="line"><span class="comment">//指定 Status3 的枚举成员为 char 型，并给Error赋值为&#x27;a&#x27;，Ok和No没有赋值，则Ok=0（ASCLL码值对应NULL），NO=98（即：a的ASCLL码+1，对应字符为b）</span></span><br></pre></td></tr></table></figure></div>
</li>
<li><p>获取枚举成员必须要在枚举名称之前加上作用域</p>
</li>
<li><p>获取到的枚举成员类型为该枚举类型，而非指定的枚举成员类型，但其记录的值不变，使用时需要将枚举成员进行强转。</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">enum class</span> <span class="title class_">test</span> :<span class="type">char</span></span><br><span class="line">&#123;</span><br><span class="line">    ok=<span class="string">&#x27;o&#x27;</span>, no=<span class="string">&#x27;n&#x27;</span>, yes=<span class="string">&#x27;y&#x27;</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">enum class</span> <span class="title class_">test</span> resut;<span class="comment">//定义枚举变量resut，class可省略，或enum和class同时省略</span></span><br><span class="line"><span class="comment">/*下面两种定义方式也可以*/</span></span><br><span class="line"><span class="keyword">enum</span> <span class="title class_">test</span> resut1;</span><br><span class="line">test resut2;</span><br><span class="line"></span><br><span class="line">resut=test::yes;<span class="comment">//给枚举变量赋初值，只能是枚举中的枚举成员，但枚举成员名前必须加上作用域，因为强类型枚举的枚举成员作用域是不共享的</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//cout&lt;&lt; resut &lt;&lt;endl;//错误，因为resut实际上是 test 枚举类型，需要强转成 char 型才能获取期望的结果</span></span><br><span class="line">cout &lt;&lt; (<span class="type">char</span>)resut &lt;&lt; endl;<span class="comment">//C风格强转</span></span><br><span class="line">cout &lt;&lt; <span class="built_in">static_cast</span>&lt;<span class="type">char</span>&gt;(test::no) &lt;&lt; endl; <span class="comment">//推荐使用C++的类型转换</span></span><br></pre></td></tr></table></figure></div>

<p>输出结果：</p>
<div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">y</span><br><span class="line">n</span><br></pre></td></tr></table></figure></div></li>
</ul>
<p>除了上述提到的一些优点，指定数据类型还可以突破原本<code>int</code>类型的最大长度限制，如：指定枚举成员类型为<code>unsigned long long</code></p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">enum class</span> <span class="title class_">test</span> :<span class="type">unsigned</span> <span class="type">long</span> <span class="type">long</span></span><br><span class="line">&#123;</span><br><span class="line">    ok, no=<span class="number">9999999999999999999</span><span class="comment">//已经远远超过 int 所能表示的最大值</span></span><br><span class="line">&#125;;</span><br><span class="line">cout &lt;&lt; <span class="built_in">static_cast</span>&lt;<span class="type">unsigned</span> <span class="type">long</span> <span class="type">long</span>&gt;(test::no) &lt;&lt; endl;</span><br></pre></td></tr></table></figure></div>

<p>输出结果：</p>
<div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">9999999999999999999</span><br></pre></td></tr></table></figure></div>

<h2 id="前置声明的写法"><a href="#前置声明的写法" class="headerlink" title="前置声明的写法"></a>前置声明的写法</h2><hr>
<p>对于前置声明，以下写法将被接受：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">enmu <span class="keyword">class</span> <span class="title class_">Clolor</span>:<span class="type">char</span>;            		<span class="comment">//前置声明枚举类</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">Foo</span><span class="params">(Color*p)</span></span>;                     	<span class="comment">//前置声明的使用</span></span><br><span class="line"><span class="comment">//....................</span></span><br><span class="line"><span class="keyword">enum class</span> <span class="title class_">Color</span>:<span class="type">char</span>&#123;RED, GREEN, BLACK, WHITE&#125;;      <span class="comment">//前置声明的定义</span></span><br></pre></td></tr></table></figure></div>

<p>分文件编写：</p>
<p>在头文件中：</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">enum class</span> <span class="title class_">LogLevel</span>;<span class="comment">//前置声明，并默认成员类型为int</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Logger</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">// ........</span></span><br><span class="line">    </span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">logging</span><span class="params">(<span class="keyword">enum</span> <span class="keyword">class</span> LogLevel level, String message)</span></span>;<span class="comment">//enum class可省略</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br></pre></td></tr></table></figure></div>

<p>在源文件中：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;头文件&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">//枚举的实现</span></span><br><span class="line"><span class="keyword">enum class</span> <span class="title class_">LogLevel</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">// ........</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// ........</span></span><br></pre></td></tr></table></figure></div>

<h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p><a class="link"   target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/164634712" >C++干货系列——“强”枚举有多强 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a><br><a class="link"   target="_blank" rel="noopener" href="https://www.runoob.com/w3cnote/cpp-enums-intro-and-strongly-typed.html" >C++ 之 enum 枚举量声明、定义、使用与强类型枚举详解 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a><br><a class="link"   target="_blank" rel="noopener" href="https://blog.csdn.net/daoming1112/article/details/54932881" >C++11强类型枚举 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a><br>推荐：<a class="link"   target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV1da411K7Kp?vd_source=03da7de0e80f9ff60fdeca7b512ba3f5" >明解 C++ Primer：19.3枚举类型 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p>
<h1 id="constexpr修饰的变量和表达式"><a href="#constexpr修饰的变量和表达式" class="headerlink" title="constexpr修饰的变量和表达式"></a><code>constexpr</code>修饰的变量和表达式</h1><h2 id="概念和使用方法"><a href="#概念和使用方法" class="headerlink" title="概念和使用方法"></a>概念和使用方法</h2><hr>
<p><code>constexpr</code>修饰的变量和表达式称为常量表达式。</p>
<p>常量表达式主要是允许一些计算发生在编译时，即发生在代码编译而不是运行的时候。</p>
<p>这是很大的优化：假如有些事情可以在编译时做，它将只做一次，而不是每次程序运行时都计算。</p>
<p>关键字：<code>constexpr</code></p>
<p>用法：使用<code>constexpr</code>修饰函数、表达式或变量<br>示例：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">GetNum</span> <span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">3</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">const</span> <span class="type">int</span> <span class="title">GetNum2</span> <span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">3</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">constexpr</span> <span class="type">int</span> <span class="title">GetNum3</span> <span class="params">()</span><span class="comment">//常量表达式，发生在编译阶段</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">3</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span> <span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// enum &#123;el = GetNum() , e2&#125;;	//编译错误	//枚举成员初始化，必须是整型常量</span></span><br><span class="line">    <span class="comment">// enum &#123;el = GetNum2() , e2&#125;; 	//加上const，同样编译错误，因为GetNum2在运行时才调用</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">enum</span> &#123;e1=<span class="built_in">GetNum3</span>() , e2&#125;; <span class="comment">//正确，编译通过，因为 GetNum3() 在编译阶段发生调用</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">constexpr</span> <span class="type">int</span> tmp = <span class="built_in">GetNum3</span>();<span class="comment">//全部发生在编译阶段</span></span><br><span class="line">    <span class="keyword">enum</span> &#123;al = tmp, a2&#125;;<span class="comment">//正确，编译通过</span></span><br><span class="line">    </span><br><span class="line">    </span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<h2 id="constexpr修饰函数的限制"><a href="#constexpr修饰函数的限制" class="headerlink" title="constexpr修饰函数的限制"></a><code>constexpr</code>修饰函数的限制</h2><hr>
<p>只对于<code>C++11</code>标准，有以下限制：</p>
<ul>
<li><p>函数中只能有一个<code>return</code>的语句，不允许有其他除了<code>ruturn</code>以外的语句（有少数特例，允许包括：<code>using</code>指令、静态断言、<code>typedef</code>）</p>
</li>
<li><p>函数必须返回值（不能是无返回值的<code>void</code>函数)</p>
</li>
<li><p>在使用前必须已有定义</p>
</li>
<li><p><code>return</code>返回语句表达式中不能使用&#x3D;&#x3D;非常量&#x3D;&#x3D;表达式的函数、全局数据，且必须是一个常量表达式</p>
</li>
</ul>
<p>在<code>C++11</code>以后的标准中（截至<code>C++20</code>）上述所有限制都不成立，使用起来和普通函数没有什么区别，对于特殊场景编译器会自动选择并优化或提示错误（参考上述示例的使用场景），这里不做过多讲述。</p>
<h2 id="constexpr修饰类的成员函数"><a href="#constexpr修饰类的成员函数" class="headerlink" title="constexpr修饰类的成员函数"></a><code>constexpr</code>修饰类的成员函数</h2><hr>
<p>在<code>C++11</code>以后的标准中（截至<code>C++20</code>）上述所有限制都不成立，使用起来和普通成员函数没有什么区别，对于特殊场景编译器会自动选择并优化，这里不做过多讲述。</p>
<h1 id="用户自定义字面量"><a href="#用户自定义字面量" class="headerlink" title="用户自定义字面量"></a>用户自定义字面量</h1><p>复制自文章：<a class="link"   target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/111369693" >C++11新特性2 - 用户定义字面量 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a>，并稍加增改。</p>
<h2 id="C-中的字面量"><a href="#C-中的字面量" class="headerlink" title="C++中的字面量"></a>C++中的字面量</h2><hr>
<p><code>C++</code> 自带4种字面量：</p>
<ul>
<li>整形 <code>123</code></li>
<li>浮点型 <code>12.3</code></li>
<li>字符 <code>&#39;1&#39;</code></li>
<li>字符串 <code>&quot;123&quot;</code></li>
</ul>
<p>字面量又可添加后缀来表明具体类型：</p>
<ul>
<li>无符号整形(<code>unsigned int</code>): <code>123u</code></li>
<li>长整形(<code>long</code>): <code>123l</code></li>
</ul>
<p>在 <code>C++03</code> 中，我们可以定义一个浮点数height</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">double</span> height = <span class="number">3.4</span></span><br></pre></td></tr></table></figure></div>

<p>那么，痛点来了，此处的<code>height</code>的单位是什么呢？米？厘米？又或是英尺？</p>
<p>在面对此类问题时，如果我们能编写如下代码，事情就会简单许多:</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">height = <span class="number">3</span>cm;</span><br><span class="line"></span><br><span class="line"><span class="comment">// ratio = (3 * 10) / 2</span></span><br><span class="line">ratio = <span class="number">3</span>cm / <span class="number">2</span>mm;</span><br></pre></td></tr></table></figure></div>

<h2 id="用户自定义字面量后缀"><a href="#用户自定义字面量后缀" class="headerlink" title="用户自定义字面量后缀"></a>用户自定义字面量后缀</h2><hr>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">long</span> <span class="type">double</span> <span class="keyword">operator</span><span class="string">&quot;&quot;</span> _cm(<span class="type">long</span> <span class="type">double</span> x) </span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">return</span> x * <span class="number">10</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">long</span> <span class="type">double</span> <span class="keyword">operator</span><span class="string">&quot;&quot;</span> _m(<span class="type">long</span> <span class="type">double</span> x) </span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">return</span> x * <span class="number">1000</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">long</span> <span class="type">double</span> <span class="keyword">operator</span><span class="string">&quot;&quot;</span> _mm(<span class="type">long</span> <span class="type">double</span> x) </span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">return</span> x;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// height = 30.0</span></span><br><span class="line"><span class="keyword">auto</span> height = <span class="number">3.0</span>_cm; </span><br><span class="line"></span><br><span class="line"><span class="comment">// length = 1230.0</span></span><br><span class="line"><span class="keyword">auto</span> length = <span class="number">1.23</span>_m;</span><br></pre></td></tr></table></figure></div>

<p>如果使用这种写法，<code>_cm</code>, <code>_m</code>, <code>_mm</code> 等函数将在运行时被调用，如果希望在编译时就调用字面量后缀函数，则需要把函数定义为 <code>constexpr</code>，例如</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">constexpr</span> <span class="type">long</span> <span class="type">double</span> <span class="keyword">operator</span><span class="string">&quot;&quot;</span> _cm(<span class="type">long</span> <span class="type">double</span> x) </span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">return</span> x * <span class="number">10</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>更进一步，我们甚至可以</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 注意，如果这里要定义函数为 constexpr</span></span><br><span class="line"><span class="comment">// 编译时需要使用 c++14 标准(-std=c++14)</span></span><br><span class="line"><span class="type">int</span> <span class="keyword">operator</span><span class="string">&quot;&quot;</span> _bin(<span class="type">const</span> <span class="type">char</span>* s, <span class="type">size_t</span> n) <span class="comment">//只需给第一个参数传参，第二个参数自动推算，测第一个参数的长度，给第二个参数赋值</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">int</span> ret = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; n; i++)</span><br><span class="line">  &#123;</span><br><span class="line">    ret = (ret &lt;&lt; <span class="number">1</span>) | (s[i] - <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> num = <span class="string">&quot;110&quot;</span>_bin; <span class="comment">// num = 6</span></span><br></pre></td></tr></table></figure></div>

<h2 id="自定义字面量的限制"><a href="#自定义字面量的限制" class="headerlink" title="自定义字面量的限制"></a><strong>自定义字面量的限制</strong></h2><hr>
<p><code>C++11 </code>只允许字面量后缀函数的参数为以下类型，即整数，浮点以及字符串：</p>
<ul>
<li><code>unsigned long long</code></li>
<li><code>long double</code></li>
<li><code>char const*</code></li>
<li><code>char const*, std::size_t</code></li>
<li><code>wchar_t const*, std::size_t</code></li>
<li><code>char16_t const*, std::size_t</code></li>
<li><code>char32_t const*, std::size_t</code></li>
</ul>
<p>返回值则无类型限制</p>
<p>参数中有<code>size_t</code>时，只需给第一个参数传参，第二个参数<code>size_t</code>自动推算。</p>
<h2 id="使用场景示例"><a href="#使用场景示例" class="headerlink" title="使用场景示例"></a>使用场景示例</h2><div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="keyword">operator</span><span class="string">&quot;&quot;</span>_cm(<span class="type">const</span> <span class="type">char</span>* str)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="function">string <span class="title">num</span><span class="params">(str)</span></span>;</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">atoi</span>(num.<span class="built_in">c_str</span>());;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">auto</span> hight = <span class="number">100</span>_cm;</span><br><span class="line">    <span class="type">int</span> weight = <span class="number">200</span>_cm;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;size = &quot;</span> &lt;&lt; hight * weight  &lt;&lt; endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>输出结果：</p>
<div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">size = 20000</span><br></pre></td></tr></table></figure></div>

<h1 id="右值引用"><a href="#右值引用" class="headerlink" title="右值引用"></a>右值引用</h1><h2 id="左值和右值的概念"><a href="#左值和右值的概念" class="headerlink" title="左值和右值的概念"></a>左值和右值的概念</h2><p>在 C++ 或者 C 语言中，一个表达式（可以是字面量、变量、对象、函数的返回值等）根据其使用场景不同，分为左值表达式和右值表达式。</p>
<p>左值指既能够出现在等号左边，也能出现在等号右边的变量；右值则是只能出现在等号右边的变量。</p>
<ul>
<li>左值是可寻址的变量，有持久性；</li>
<li>右值一般是不可寻址的常量，或在表达式求值过程中创建的无名临时对象，短暂性的。</li>
</ul>
<p>左值和右值主要的区别之一是左值可以被修改，而右值不能。</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> a; <span class="comment">// a 为左值</span></span><br><span class="line">a = <span class="number">3</span>; <span class="comment">// 3 为右值</span></span><br></pre></td></tr></table></figure></div>

<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">func</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> a;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">mian</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> a = <span class="built_in">func</span>();<span class="comment">//a为右值，func的返回值是右值，无法直接对func的返回值进行修改</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<h2 id="左值引用和右值引用"><a href="#左值引用和右值引用" class="headerlink" title="左值引用和右值引用"></a>左值引用和右值引用</h2><h3 id="左值引用"><a href="#左值引用" class="headerlink" title="左值引用"></a>左值引用</h3><p>详见文件：<a href=".%5CC++%E5%9F%BA%E7%A1%80.md">C++基础.md</a>——引用篇，详解</p>
<h3 id="右值引用-1"><a href="#右值引用-1" class="headerlink" title="右值引用"></a>右值引用</h3><p><code>C++98/03</code>标准中就有引用，使用 <code>&amp;</code> 表示。但此种引用方式有一个缺陷，即正常情况下只能操作<code>C++</code>中的左值，无法对右值添加引用。</p>
<p>示例：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> num = <span class="number">10</span>;</span><br><span class="line"><span class="type">int</span> &amp;b = num; <span class="comment">//正确</span></span><br><span class="line"><span class="type">int</span> &amp;c = <span class="number">10</span>; <span class="comment">//错误</span></span><br></pre></td></tr></table></figure></div>

<p>如上所示，编译器允许我们为<code>num</code>左值建立一个引用，但不可以为<code>10</code>这个右值建立引用。因此，<code>C++98/03</code>标准中的引用又称为左值引用。</p>
<p>注意，虽然<code>C++98/03</code>标准不支持为右值建立非常量左值引用，但允许使用常量左值引用操作右值。也就是说，常量左值引用既可以操作左值，也可以操作右值，例如：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> num = <span class="number">10</span>;</span><br><span class="line"><span class="type">const</span> <span class="type">int</span> &amp;b = num;</span><br><span class="line"><span class="type">const</span> <span class="type">int</span> &amp;c = <span class="number">10</span>;</span><br></pre></td></tr></table></figure></div>

<p>右值往往是没有名称的，因此要使用它只能借助引用的方式。</p>
<p>这就产生一个问题，实际开发中我们可能需要对右值进行修改（实现移动语义时就需要），显然左值引用的方式是行不通的。</p>
<p><code>C++11</code>标准新引入了另一种引用方式，称为右值引用，用 <code>&amp;&amp;</code>表示。</p>
<p><code>C++</code>标准委员会在选定右值引用符号时，既希望能选用现有<code>C++</code>内部已有的符号，还不能与<code>C++ 98 /03</code> 标准产生冲突，最终选定了 2 个 <code>&amp;</code> 表示右值引用。</p>
<p>需要注意的，和声明左值引用一样，右值引用也必须立即进行初始化操作，且只能使用右值进行初始化，比如：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> num = <span class="number">10</span>;</span><br><span class="line"><span class="type">int</span> &amp;&amp; a = num;  <span class="comment">//错误，左值不能被右值引用</span></span><br><span class="line"><span class="type">int</span> &amp;&amp; a = <span class="number">10</span>;</span><br></pre></td></tr></table></figure></div>

<p>和常量左值引用不同的是，右值引用还可以对右值进行修改。例如：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> &amp;&amp; a = <span class="number">10</span>;</span><br><span class="line">a = <span class="number">100</span>;</span><br><span class="line">cout &lt;&lt; a &lt;&lt; endl;</span><br></pre></td></tr></table></figure></div>

<p>程序输出结果为 <code>100</code>。</p>
<p><code>C++</code>语法上是支持定义常量右值引用的，例如：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">const</span> <span class="type">int</span>&amp;&amp; a = <span class="number">10</span>;</span><br></pre></td></tr></table></figure></div>

<p>但这种定义出来的右值引用并无实际用处。</p>
<p>一方面，右值引用主要用于移动语义和完美转发，其中前者需要有修改右值的权限</p>
<p>其次，常量右值引用的作用就是引用一个不可修改的右值，这项工作完全可以交给常量左值引用完成。</p>
<table>
<caption>
C++左值引用和右值引用</caption>
<tbody>
<tr>
<th colspan="1" rowspan="2">
引用类型</th>
<th colspan="4" rowspan="1">
可以引用的值类型</th>
<th colspan="1" rowspan="2">
使用场景</th>
</tr>
<tr>
<th>
非常量左值</th>
<th>
常量左值</th>
<th>
非常量右值</th>
<th>
常量右值</th>
</tr>
<tr>
<td>
非常量左值引用</td>
<td>
Y</td>
<td>
N</td>
<td>
N</td>
<td>
N</td>
<td>
无</td>
</tr>
<tr>
<td>
常量左值引用</td>
<td>
Y</td>
<td>
Y</td>
<td>
Y</td>
<td>
Y</td>
<td>
常用于类中构建拷贝构造函数</td>
</tr>
<tr>
<td>
非常量右值引用</td>
<td>
N</td>
<td>
N</td>
<td>
Y</td>
<td>
N</td>
<td>
移动语义、完美转发</td>
</tr>
<tr>
<td>
常量右值引用</td>
<td>
N</td>
<td>
N</td>
<td>
Y</td>
<td>
Y</td>
<td>
无实际用途</td>
</tr>
</tbody>
</table>

<p>表中，Y 表示支持，N 表示不支持。</p>
<p><code>C++11</code>标准中对右值做了更细致的划分，分别称为纯右值（Pure value，简称 pvalue）和将亡值（eXpiring value，简称 xvalue ）。</p>
<p>其中纯右值就是<code>C++98/03</code>标准中的右值，而将亡值则指的是和右值引用相关的表达式（比如某函数返回的<code>T &amp;&amp;</code>类型的表达式）。</p>
<h1 id="移动语义"><a href="#移动语义" class="headerlink" title="移动语义"></a>移动语义</h1><h2 id="为什么需要移动语义"><a href="#为什么需要移动语义" class="headerlink" title="为什么需要移动语义"></a>为什么需要移动语义</h2><p>如果一个对象中有堆区资源，需要编写拷贝构造函数和赋值函数，实现深拷贝。</p>
<p>深拷贝把对象中的堆区资源复制了一份，如果源对象（被拷贝的对象）是临时对象，拷贝完就没什么用了，这样会造成没有意义的资源申请和释放操作。</p>
<p>同时临时对象的维护（创建和销毁）对性能有严重影响。</p>
<p>如果能够直接使用源对象拥有的资源，可以节省资源申请和释放的时间。</p>
<p>C++11新增加的移动语义就能够做到这一点。</p>
<p>实现移动语义要增加两个函数：移动构造函数和移动赋值函数。</p>
<p>转移语义可以将资源（堆，系统对象等）从一个对象转移到另一个对象，这样能够减少不必要的临时对象的创建、拷贝以及销毁，能够大幅度提高C++应用程序的性能。</p>
<p>右值引用就是用来支持转移语义的。</p>
<p>转移语义是和拷贝语义相对的，可以类比文件的剪切与拷贝，当我们将文件从一个目录拷贝到另一个目录时，速度比剪切慢很多。</p>
<p>通过转移语义，临时对象中的资源能够转移其它的对象里。</p>
<h2 id="转移构造函数"><a href="#转移构造函数" class="headerlink" title="转移构造函数"></a>转移构造函数</h2><p>移动构造函数是一种特殊的构造函数，用于在对象之间进行资源的移动而不是复制。</p>
<p>移动构造函数通常用于以下情况：</p>
<ul>
<li>当使用右值引用（使用双&amp;&amp;符号）绑定到一个临时对象时，移动构造函数将被调用。</li>
<li>当使用<code>std::move</code>函数将一个对象强制转换为右值引用时，移动构造函数将被调用。</li>
</ul>
<p>移动构造函数的目的是将资源（例如堆分配的内存、文件句柄等）从一个对象转移到另一个对象，而不是复制这些资源。</p>
<p>通过移动而不是复制资源，可以显著提高性能，避免不必要的内存分配和复制操作。</p>
<p>语法：</p>
<p>移动构造函数的语法与普通构造函数的语法非常相似，只是在参数列表前加上了双&amp;&amp;符号来表示右值引用。</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">ClassName</span>(ClassName&amp;&amp; other);  <span class="comment">// 移动构造函数</span></span><br></pre></td></tr></table></figure></div>

<p>在移动构造函数中，参数<code>other</code>是一个右值引用，表示要移动资源的对象。在函数体内，你可以使用移动操作符<code>std::move</code>来将资源从<code>other</code>对象转移给当前对象。</p>
<p>移动构造函数通常会将源对象的成员指针设置为<code>nullptr</code>，以避免在析构函数中重复释放资源。</p>
<p>这是因为资源的所有权已经转移到了目标对象。</p>
<p>移动构造函数通常也可以声明为<code>noexcept</code>，以表明它不会抛出异常。这对于某些情况下的优化和语义保证很重要。</p>
<p>下面是一个完整的示例，展示了移动构造函数的语法和用法：</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyClass</span> </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="type">int</span>* data;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 默认构造函数</span></span><br><span class="line">    <span class="built_in">MyClass</span>() : <span class="built_in">data</span>(<span class="literal">nullptr</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;Default constructor called.&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 移动构造函数</span></span><br><span class="line">    <span class="built_in">MyClass</span>(MyClass&amp;&amp; other) <span class="keyword">noexcept</span> : <span class="built_in">data</span>(<span class="literal">nullptr</span>) </span><br><span class="line">    &#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;Move constructor called.&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">        data = other.data;</span><br><span class="line">        other.data = <span class="literal">nullptr</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 析构函数</span></span><br><span class="line">    ~<span class="built_in">MyClass</span>() </span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span> (data != <span class="literal">nullptr</span>) </span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">delete</span> data;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    MyClass source;</span><br><span class="line">    source.data = <span class="keyword">new</span> <span class="built_in">int</span>(<span class="number">42</span>);</span><br><span class="line"></span><br><span class="line">    <span class="function">MyClass <span class="title">destination</span><span class="params">(std::move(source))</span></span>;</span><br><span class="line"></span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;source.data: &quot;</span> &lt;&lt; source.data &lt;&lt; std::endl;</span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;destination.data: &quot;</span> &lt;&lt; destination.data &lt;&lt; std::endl;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>在上面的示例中，我们定义了一个<code>MyClass</code>类，包含了一个指针成员变量<code>data</code>。我们使用移动构造函数将资源从<code>source</code>对象移动到<code>destination</code>对象。</p>
<p>在移动构造函数的参数列表中，使用了<code>ClassName&amp;&amp;</code>的形式来表示右值引用。</p>
<p>需要注意，一旦资源被移动到目标对象，源对象的资源将不再有效。</p>
<p>因此，应该小心使用移动构造函数，确保正确处理资源所有权和对象的状态。</p>
<h2 id="转移赋值函数"><a href="#转移赋值函数" class="headerlink" title="转移赋值函数"></a>转移赋值函数</h2><p>和拷贝构造函数类似，有几点需要注意：</p>
<ul>
<li>参数（右值）的符号必须是右值引用符号，即“&amp;&amp;”。</li>
<li>参数（右值）不可以是常量，因为我们需要修改右值。</li>
<li>参数(右值)的资源链接和标记必须修改，否则，右值的析构函数就会释放资源，转移到新对象的资源也就无效了。</li>
</ul>
<p>有了右值引用和转移语义，我们在设计和实现类时，对于需要动态申请大量资源的类，应该设计转移构造函数和转移赋值函数，以提高应用程序的效率。</p>
<h2 id="std-move"><a href="#std-move" class="headerlink" title="std::move"></a><code>std::move</code></h2><p>对于一个左值，会调用拷贝构造函数，但是有些左值是局部变量，生命周期也很短，能不能也移动而不是拷贝呢?</p>
<p>C++11为了解决这个问题，提供了<code>std:move()</code>方法来将左值转义为右值，从而方便使用移动语义。</p>
<p>它其实就是告诉编译器，虽然我是一个左值，但不要对我用拷贝构造函数，用移动构造函数。</p>
<p>左值对象被转移资源后，不会立刻析构，只有在离开自己的作用域的时候才会析构，如果继续使用左值中的资源，可能会发生意想不到的错误。</p>
<p>如果没有提供移动构造&#x2F;赋值函数，只提供了拷贝构造&#x2F;赋值函数，编译器找不到移动构造&#x2F;赋值函数就去寻找拷贝构造&#x2F;赋值函数。</p>
<p>C++11中的所有容器都实现了移动语义，避免对含有资源的对象发生无谓的拷贝。</p>
<p>移动语义对于拥有资源（如内存、文件句柄)的对象有效，如果是基本类型，使用移动语义没有意义。</p>
<p>示例：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> a;</span><br><span class="line"><span class="type">int</span> &amp;&amp;r1 = a;<span class="comment">//编译失败</span></span><br><span class="line"><span class="type">int</span> &amp;&amp;r2 = std:<span class="built_in">move</span>(a);<span class="comment">//编译通过</span></span><br></pre></td></tr></table></figure></div>

<h1 id="完美转发"><a href="#完美转发" class="headerlink" title="完美转发"></a>完美转发</h1><p>完美转发适用于这样的场景：</p>
<p>需要将一组参数原封不动的传递给另一个函数。</p>
<p>“原封不动”不仅仅是参数的值不变，在C++中，除了参数值之外，还有一下两组属性：</p>
<p>左值&#x2F;右值和 const&#x2F;non-const。</p>
<p>完美转发就是在参数传递过程中，所有这些属性和参数值都不能改变，同时，而不产生额外的开销，就好像转发者不存在一样。</p>
<p>在泛型函数中，这样的需求非常普遍。</p>
<h1 id="类型转换"><a href="#类型转换" class="headerlink" title="类型转换"></a>类型转换</h1><h2 id="const-cast"><a href="#const-cast" class="headerlink" title="const_cast"></a><code>const_cast</code></h2><hr>
<p><code>const_cast</code>是<code>C++</code>中的一个类型转换运算符，用于将<code>const</code>和<code>volatile</code>限定符从指针或引用类型中移除。</p>
<p>它的语法如下：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">const_cast</span>&lt;new_type&gt;(expression)</span><br></pre></td></tr></table></figure></div>

<p>其中，<code>new_type</code>是要转换成的类型，<code>expression</code>是要转换的表达式。</p>
<p>举个例子，假设有一个<code>const int</code>类型的变量，我们想要修改它的值，可以使用<code>const_cast</code>将其转换成<code>int</code>类型，然后进行修改。</p>
<p>示例代码如下：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">const</span> <span class="type">int</span> a = <span class="number">10</span>;</span><br><span class="line"><span class="type">int</span>&amp; b = <span class="built_in">const_cast</span>&lt;<span class="type">int</span>&amp;&gt;(a);</span><br><span class="line">b = <span class="number">20</span>;</span><br><span class="line">std::cout &lt;&lt; a &lt;&lt; std::endl; <span class="comment">// 输出10</span></span><br><span class="line">std::cout &lt;&lt; b &lt;&lt; std::endl; <span class="comment">// 输出20</span></span><br></pre></td></tr></table></figure></div>

<p>需要注意的是，使用<code>const_cast</code>进行类型转换可能会导致未定义行为，因为它可以打破<code>const</code>限定符的保护。</p>
<p>因此，在使用<code>const_cast</code>时需要谨慎，确保不会对原始对象造成损害。</p>
<h2 id="reinterpret-cast"><a href="#reinterpret-cast" class="headerlink" title="reinterpret_cast"></a><code>reinterpret_cast</code></h2><hr>
<p><code>reinterpret_cast</code>是<code>C++</code>中的一个类型转换运算符，用于进行底层的类型转换。这是一个很危险的转换，编译器不会做任何类型安全的检查。</p>
<p>它可以将一个指针或引用转换为任何其他类型的指针或引用，甚至可以将一个指针转换为一个整数类型。</p>
<p>它的语法如下：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">reinterpret_cast</span>&lt;new_type&gt;(expression)</span><br></pre></td></tr></table></figure></div>

<p>其中，<code>new_type</code>是要转换成的类型，<code>expression</code>是要转换的表达式。</p>
<p>举个例子，假设有一个<code>int</code>类型的变量，我们想要将它的值转换成一个指针，可以使用<code>reinterpret_cast</code>。</p>
<p>示例代码如下：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> a = <span class="number">10</span>;</span><br><span class="line"><span class="type">int</span>* p = <span class="built_in">reinterpret_cast</span>&lt;<span class="type">int</span>*&gt;(a);</span><br><span class="line">*p = <span class="number">20</span>;</span><br><span class="line">std::cout &lt;&lt; a &lt;&lt; std::endl; <span class="comment">// 输出20</span></span><br><span class="line">std::cout &lt;&lt; *p &lt;&lt; std::endl; <span class="comment">// 输出20</span></span><br></pre></td></tr></table></figure></div>

<p>需要注意的是，使用<code>reinterpret_cast</code>进行类型转换可能会导致未定义行为，因为它可以将一个指针转换为一个不相关的类型。</p>
<p>因此，在使用<code>reinterpret_cast</code>时需要谨慎，确保转换的类型是合法的。</p>
<h2 id="dynamic-cast"><a href="#dynamic-cast" class="headerlink" title="dynamic_cast"></a><code>dynamic_cast</code></h2><hr>
<p><code>dynamic_cast</code>是<code>C++</code>中的一个类型转换运算符，用于在运行时进行类型转换。</p>
<p>它主要用于将父类指针或引用转换为子类指针或引用（这种转换也称下行转换），或者将<code>void</code>指针转换为其他类型的指针。</p>
<p>它的语法如下：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">dynamic_cast</span>&lt;new_type&gt;(expression)</span><br></pre></td></tr></table></figure></div>

<p>其中，<code>new_type</code>是要转换成的类型，<code>expression</code>是要转换的表达式。</p>
<p>举个例子，假设有一个基类<code>Animal</code>和两个派生类<code>Cat</code>和<code>Dog</code>，我们想要将一个<code>Animal</code>指针转换成<code>Cat</code>指针，可以使用<code>dynamic_cast</code>。</p>
<p>示例代码如下：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Animal</span> </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">makeSound</span><span class="params">()</span> </span>&#123;&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Cat</span> : <span class="keyword">public</span> Animal </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">makeSound</span><span class="params">()</span> <span class="keyword">override</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;Meow!&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Dog</span> : <span class="keyword">public</span> Animal </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">makeSound</span><span class="params">()</span> <span class="keyword">override</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;Woof!&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Animal* animal = <span class="keyword">new</span> <span class="built_in">Cat</span>();</span><br><span class="line">    Cat* cat = <span class="built_in">dynamic_cast</span>&lt;Cat*&gt;(animal);</span><br><span class="line">    <span class="keyword">if</span> (cat) </span><br><span class="line">    &#123;</span><br><span class="line">        cat-&gt;<span class="built_in">makeSound</span>(); <span class="comment">// 输出Meow!</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">delete</span> animal;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>使用<code>dynamic_cast</code>进行类型转换时，如果转换失败，会返回一个空指针或引用。</p>
<p>因此，在使用<code>dynamic_cast</code>时需要进行判断，确保转换成功。</p>
<h2 id="上行转换和下行转换"><a href="#上行转换和下行转换" class="headerlink" title="上行转换和下行转换"></a>上行转换和下行转换</h2><hr>
<p>在C++中，上行转换（upcasting）和下行转换（downcasting）是与继承和多态相关的概念。</p>
<p>上行转换是指将子类的指针或引用隐式地转换为父类的指针或引用。</p>
<p>这种转换是安全的，因为子类对象包含了父类的成员，因此可以通过父类的接口来访问子类的成员。</p>
<p>例如：</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Animal</span> </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">eat</span><span class="params">()</span> </span></span><br><span class="line"><span class="function">     </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Animal is eating.&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Dog</span> : <span class="keyword">public</span> Animal </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">eat</span><span class="params">()</span> <span class="keyword">override</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Dog is eating.&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">bark</span><span class="params">()</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Dog is barking.&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Dog dog;</span><br><span class="line">    Animal* animalPtr = &amp;dog;  <span class="comment">// 上行转换</span></span><br><span class="line">    animalPtr-&gt;<span class="built_in">eat</span>();  <span class="comment">// 调用的是子类的 eat() 函数</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>在上面的示例中，<code>Dog</code> 类是 <code>Animal</code> 类的子类。通过将 <code>Dog</code> 类的对象的指针赋值给 <code>Animal</code> 类的指针，发生了上行转换。</p>
<p>即 <code>animalPtr</code> 指向的是 <code>Dog</code> 类的对象，但只能通过 <code>Animal</code> 类的接口来访问。</p>
<p>下行转换是指将父类的指针或引用显式地转换为子类的指针或引用。这种转换需要使用 <code>dynamic_cast</code> 运算符（下一篇将讲到），并且在运行时进行类型检查，因为并非所有父类的指针或引用都可以转换为子类类型。</p>
<p>例如：</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Animal</span> </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">eat</span><span class="params">()</span> </span></span><br><span class="line"><span class="function">     </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Animal is eating.&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Dog</span> : <span class="keyword">public</span> Animal </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">eat</span><span class="params">()</span> <span class="keyword">override</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Dog is eating.&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">bark</span><span class="params">()</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Dog is barking.&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Animal animal;</span><br><span class="line">    Animal* animalPtr = &amp;animal;</span><br><span class="line">    Dog* dogPtr = <span class="built_in">dynamic_cast</span>&lt;Dog*&gt;(animalPtr);  <span class="comment">// 下行转换，这段代码的作用是将父类指针animalPtr转换为子类指针dogPtr</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (dogPtr != <span class="literal">nullptr</span>) </span><br><span class="line">    &#123;</span><br><span class="line">        dogPtr-&gt;<span class="built_in">bark</span>();  <span class="comment">// 通过子类指针访问子类的成员</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span> </span><br><span class="line">    &#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Downcasting failed.&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>在上面的示例中，<code>dynamic_cast</code> 运算符将 <code>Animal</code> 类的指针 <code>animalPtr</code> 转换为 <code>Dog</code> 类的指针 <code>dogPtr</code>。</p>
<p>由于 <code>animalPtr</code> 实际指向的是 <code>Animal</code> 类的对象，而不是 <code>Dog</code> 类的对象，所以转换失败，<code>dogPtr</code> 的值为 <code>nullptr</code>。</p>
<p>输出结果：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Downcasting failed.</span><br></pre></td></tr></table></figure></div>

<p>因此，建议在进行下行转换之前，先使用 <code>dynamic_cast</code> 运算符进行类型检查，以确保转换的安全性。</p>
<p>如果不使用 <code>dynamic_cast</code> 运算符进行类型检查，虽然可以转换成功，但是当调用子类成员时程序就可能会发生错误。</p>
<p>上行转换是安全的，因为子类对象是父类对象的扩展，可以通过父类接口访问子类的成员。</p>
<p>下行转换需要进行类型检查，因为父类对象的指针或引用并不总是指向子类对象。</p>
<p>如果使用C风格的强制类型转换，将父类指针或引用直接转换为子类指针或引用，而不使用<code>dynamic_cast</code>进行类型检查，可能会导致以下问题：</p>
<ul>
<li><p>未进行类型检查：</p>
<p>C风格的强制类型转换不会进行类型检查，因此无法确保父类指针或引用指向的对象的确是子类对象。如果父类指针或引用并不指向子类对象，而你进行了转换，将会导致不可预测的行为和潜在的错误。</p>
</li>
<li><p>切割对象：</p>
<p>如果你使用强制类型转换将父类指针或引用转换为子类指针或引用，而父类对象中含有子类特有的成员或虚函数，这些子类特有的内容将会被切割掉，导致在转换后无法访问这些成员或调用这些虚函数。</p>
</li>
<li><p>安全性问题：</p>
<p>由于没有进行类型检查，使用强制类型转换可能会破坏C++的类型系统和继承体系的安全性。这可能导致程序在运行时产生未定义行为、内存访问错误或崩溃。</p>
</li>
</ul>
<p>示例：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Animal</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">eat</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Animal is eating.&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Dog</span> : <span class="keyword">public</span> Animal</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">eat</span><span class="params">()</span> <span class="keyword">override</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Dog is eating.&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">bark</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Dog is barking.&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">    string name = <span class="string">&quot;ggbom&quot;</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Dog* dogPtr =(Dog*) <span class="keyword">new</span> Animal*; </span><br><span class="line">    cout &lt;&lt;<span class="string">&quot;dog&#x27;s name:&quot;</span> &lt;&lt; dogPtr-&gt;name &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;dog&#x27;s name length:&quot;</span> &lt;&lt; dogPtr-&gt;name.<span class="built_in">length</span>() &lt;&lt; endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>上述这段代码运行的结果是不确定的，有时会报错提示读取写入内存冲突，有时会使程序直接崩溃，有时则能打印出<code>dog&#39;s name:</code> 和<code>dog&#39;s name length:0</code>，但是<code>dogPtr-&gt;name</code>的部分是空白，有时则只打印<code>dog&#39;s name:</code>，然后程序直接结束。</p>
<p>因此，只在C++中使用<code>dynamic_cast</code>进行下行转换，以确保类型安全性和正确性。</p>
<p><code>dynamic_cast</code>会在运行时进行类型检查，只有在父类指针或引用确实指向子类对象时才会返回有效的子类指针或引用。。</p>
<h2 id="static-cast"><a href="#static-cast" class="headerlink" title="static_cast"></a><code>static_cast</code></h2><hr>
<p><code>static_cast</code>是<code>C++</code>中的一个类型转换运算符，用于进行静态类型转换。</p>
<p>用于一些基本类型的转换和有继承关系的父类和子类指针或引用间的转换。</p>
<p><code>static_cast</code>不会产生动态转换的类型安全检查的开销，由程序员来确保转换是安全的。</p>
<p>它的语法如下：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">static_cast</span>&lt;new_type&gt;(expression)</span><br></pre></td></tr></table></figure></div>

<p>其中，<code>new_type</code>是要转换成的类型，<code>expression</code>是要转换的表达式。</p>
<p>举个例子，假设有一个int类型的变量，我们想要将它的值转换成一个<code>double</code>类型，可以使用<code>static_cast</code>。</p>
<p>示例代码如下：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> a = <span class="number">10</span>;</span><br><span class="line"><span class="type">double</span> b = <span class="built_in">static_cast</span>&lt;<span class="type">double</span>&gt;(a);</span><br><span class="line">std::cout &lt;&lt; b &lt;&lt; std::endl; <span class="comment">// 输出10.0</span></span><br></pre></td></tr></table></figure></div>

<p>需要注意的是，使用<code>static_cast</code>进行类型转换时，如果转换不安全，可能会导致未定义行为。</p>
<p>因此，在使用<code>static_cast</code>时需要谨慎，确保转换的类型是安全的。</p>
<h1 id="lambda表达式"><a href="#lambda表达式" class="headerlink" title="lambda表达式"></a>lambda表达式</h1><p>lambda表达式是一种用于创建匿名函数的简洁语法。</p>
<p>lambda表达式可以用作函数对象，并且可以捕获上下文中的变量。</p>
<p>下面是一个使用lambda表达式的示例：</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;functional&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> factor = <span class="number">2</span>;</span><br><span class="line">    std::function&lt;<span class="type">int</span>(<span class="type">int</span>)&gt; func = [factor](<span class="type">int</span> x) &#123; <span class="keyword">return</span> factor * x; &#125;;</span><br><span class="line">    std::cout &lt;&lt; <span class="built_in">func</span>(<span class="number">3</span>) &lt;&lt; std::endl;  <span class="comment">// 输出：6</span></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>在上面的示例中，lambda表达式<code>[factor](int x) &#123; return factor * x; &#125;</code>定义了一个函数对象，它接受一个<code>int</code>参数并返回<code>factor * x</code>的结果。</p>
<p>在lambda表达式中，我们通过方括号<code>[]</code>捕获了外部变量<code>factor</code>，以便在lambda表达式中使用。</p>
<p>lambda表达式的一般形式是：</p>
<ul>
<li><code>[捕获列表](参数列表) -&gt; 返回类型 &#123; 函数体 &#125;</code></li>
<li>其中捕获列表指定需要捕获的外部变量，参数列表指定函数的参数，返回类型指定函数的返回类型，函数体则是函数的实现。</li>
</ul>
<p>lambda表达式还支持各种功能，如可变捕获（允许修改被捕获的变量）、自动类型推导、多行函数体等。</p>
<p>它们非常灵活，并且通常与算法函数（如<code>std::for_each</code>、<code>std::transform</code>等）一起使用，用于对容器中的元素进行处理。</p>
<p>其中<code>参数列表</code>、在函数无参时可以省略，<code>-&gt;</code>、<code>返回值类型</code>也可以省略，省略后将由编译器自动推导。<code>[捕获列表]</code>和<code>&#123;函数体&#125;</code>不可以省略，因此最简单的lambda表达式的形式是这样的：<code>[]&#123;&#125;;</code>，解释：这是一个匿名函数对象，无参、无返回值、函数体内部为空实现，捕获列表为空。</p>
<p>关于捕获列表：</p>
<p>捕获列表用于指定Lambda表达式中要捕获的外部变量。</p>
<p>将lambda表达式理解成函数，如果需要在函数体内部使用到函数体外的变量和表达式，那么就需要在捕获列表中指明需要用到的表达式。</p>
<p>可以使用引用捕获或值捕获，使用引用捕获时当在函数体内部对捕获的变量进行了修改，那么外部变量原来的值也会发生改变，值捕获相当于拷贝了一份，函数体内部的操作不会影响原来的值，同样使用值捕获也不能在函数体内部对捕获的变量进行修改。</p>
<p>下面是捕获列表的几种常见写法：</p>
<ol>
<li><p><code>[&amp;]</code>：使用引用捕获方式，表示捕获外部作用域中的所有变量（按引用方式）。</p>
</li>
<li><p><code>[=]</code>：使用直接捕获方式，表示捕获外部作用域中的所有变量（按值方式）。</p>
</li>
<li><p><code>[x, &amp;y]</code>：捕获外部作用域中的变量<code>x</code>（按值方式）和变量<code>y</code>（按引用方式）。</p>
</li>
<li><p><code>[&amp;z, this]</code>：捕获外部作用域中的变量<code>z</code>（按引用方式）和当前对象指针<code>this</code>（按值方式）。</p>
</li>
<li><p><code>[]</code>：不捕获任何外部变量。</p>
</li>
</ol>
<p>在捕获列表中，<code>&amp;</code>表示按引用捕获，<code>=</code>表示按值捕获。</p>
<p>捕获列表中的变量名可以是当前作用域中的任何变量，包括函数参数、局部变量等。使用逗号将不同的变量进行分隔。</p>
<p>示例代码1：</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> x = <span class="number">5</span>;</span><br><span class="line">    <span class="type">int</span> y = <span class="number">10</span>;</span><br><span class="line">    <span class="type">int</span> z = <span class="number">15</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 按引用捕获x和y，按值捕获z</span></span><br><span class="line">    <span class="keyword">auto</span> lambda1 = [&amp;x, &amp;y, z]() </span><br><span class="line">    &#123;</span><br><span class="line">        x++;</span><br><span class="line">        y++;</span><br><span class="line">        <span class="comment">// z++; // 错误，无法修改被值捕获的变量</span></span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;x: &quot;</span> &lt;&lt; x &lt;&lt; std::endl;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;y: &quot;</span> &lt;&lt; y &lt;&lt; std::endl;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;z: &quot;</span> &lt;&lt; z &lt;&lt; std::endl;</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 按值捕获x和y，不捕获其他变量</span></span><br><span class="line">    <span class="keyword">auto</span> lambda2 = [=]() </span><br><span class="line">    &#123;</span><br><span class="line">        <span class="comment">// x++; // 错误，无法修改被值捕获的变量</span></span><br><span class="line">        <span class="comment">// y++; // 错误，无法修改被值捕获的变量</span></span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;x: &quot;</span> &lt;&lt; x &lt;&lt; std::endl;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;y: &quot;</span> &lt;&lt; y &lt;&lt; std::endl;</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">lambda1</span>(); <span class="comment">// 输出：x: 6, y: 11, z: 15</span></span><br><span class="line">    <span class="built_in">lambda2</span>(); <span class="comment">// 输出：x: 5, y: 10</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>在这个示例中，我们定义了两个Lambda表达式：<code>lambda1</code>和<code>lambda2</code>。<code>lambda1</code>的捕获列表使用了引用捕获和值捕获的组合，它按引用捕获了变量<code>x</code>和<code>y</code>，按值捕获了变量<code>z</code>。<code>lambda2</code>的捕获列表使用了纯值捕获，它按值捕获了变量<code>x</code>和<code>y</code>。你可以尝试运行这段代码，观察输出结果，以加深对捕获列表的理解。</p>
<p>需要注意的是，捕获列表中的变量名必须是在Lambda表达式的外部作用域中可见的。</p>
<p>对于捕获的变量，如果在Lambda表达式内部对其进行修改，使用引用捕获的变量会影响到外部作用域中的原始变量，而使用直接捕获的变量只会修改Lambda表达式内部的副本，不会影响外部作用域中的原始变量。</p>
<p>示例代码2：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> x = <span class="number">5</span>;</span><br><span class="line">    <span class="type">int</span> y = <span class="number">10</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 引用捕获示例</span></span><br><span class="line">    <span class="keyword">auto</span> lambdaRef = [&amp;]() </span><br><span class="line">    &#123;</span><br><span class="line">        x++;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;x: &quot;</span> &lt;&lt; x &lt;&lt; std::endl;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;y: &quot;</span> &lt;&lt; y &lt;&lt; std::endl;</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 直接捕获示例</span></span><br><span class="line">    <span class="keyword">auto</span> lambdaCopy = [=]() </span><br><span class="line">    &#123;</span><br><span class="line">        <span class="comment">// y++; // 错误，无法修改被值捕获的变量</span></span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;x: &quot;</span> &lt;&lt; x &lt;&lt; std::endl;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;y: &quot;</span> &lt;&lt; y &lt;&lt; std::endl;</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">lambdaRef</span>();  <span class="comment">// 输出：x: 6, y: 10</span></span><br><span class="line">    <span class="built_in">lambdaCopy</span>(); <span class="comment">// 输出：x: 5, y: 10</span></span><br><span class="line"></span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;x: &quot;</span> &lt;&lt; x &lt;&lt; std::endl;</span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;y: &quot;</span> &lt;&lt; y &lt;&lt; std::endl;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure></div>









<h1 id="std-function"><a href="#std-function" class="headerlink" title="std::function"></a><code>std::function</code></h1><h2 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h2><p>当你在C++中需要将函数作为参数传递或者将其存储在容器中时，<code>std::function</code>和lambda表达式是两个非常有用的工具。</p>
<p>它们都是C++11引入的特性，可以用于创建可调用对象。</p>
<p><code>std::function</code>是一个通用的函数封装器，可以用来存储、复制和调用任何可调用对象（函数指针、函数对象、成员函数指针等）。</p>
<p>使用<code>std::function</code>，你可以将函数包装在一个类型安全的容器中，并将其传递给其他函数或算法进行处理。</p>
<p>下面是一个使用<code>std::function</code>的简单示例：</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;functional&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">add</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b)</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> a + b;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    std::function&lt;<span class="type">int</span>(<span class="type">int</span>, <span class="type">int</span>)&gt; func = add;</span><br><span class="line">    std::cout &lt;&lt; <span class="built_in">func</span>(<span class="number">3</span>, <span class="number">4</span>) &lt;&lt; std::endl;  <span class="comment">// 输出：7</span></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>在上面的示例中，<code>std::function&lt;int(int, int)&gt;</code>表示一个可调用对象，它接受两个<code>int</code>参数并返回一个<code>int</code>值。</p>
<p>通过将<code>add</code>函数分配给<code>func</code>，我们可以通过<code>func(3, 4)</code>调用<code>add</code>函数。</p>
<p>在C++中，<code>std::function</code>是一个通用的函数封装器，它可以存储、复制和调用任何可调用对象，例如函数、函数指针、Lambda 表达式、成员函数指针等。<code>std::function</code>提供了一种将函数对象与其参数类型和返回类型解耦的方式，使得函数对象可以像普通函数一样传递和使用。</p>
<p><code>std::function</code>定义在头文件 <code>&lt;functional&gt;</code> 中，它是一个类模板，其基本语法如下：</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">std::function&lt;返回类型(参数类型)&gt; func;</span><br></pre></td></tr></table></figure></div>

<p>其中，<code>返回类型</code>是函数对象的返回类型，而<code>参数类型</code>是函数对象的参数类型。下面来详细讲解<code>std::function</code>的一些特性和用法：</p>
<h2 id="std-function的创建和调用"><a href="#std-function的创建和调用" class="headerlink" title="std::function的创建和调用"></a><code>std::function</code>的创建和调用</h2><p>要创建一个<code>std::function</code>对象，可以通过函数指针、函数对象、Lambda 表达式等来进行初始化，</p>
<p>可以像调用普通函数一样，使用括号运算符来调用<code>std::function</code>对象。</p>
<p>如下所示：</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;functional&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 函数对象</span></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">Functor</span> </span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">operator</span><span class="params">()</span><span class="params">(<span class="type">int</span> x, <span class="type">int</span> y)</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> x + y;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//普通函数</span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">add</span><span class="params">(<span class="type">int</span> x, <span class="type">int</span> y)</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> x + y;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    std::function&lt;<span class="type">int</span>(<span class="type">int</span>, <span class="type">int</span>)&gt; func1 = add;</span><br><span class="line">    std::function&lt;<span class="type">int</span>(<span class="type">int</span>, <span class="type">int</span>)&gt; func2 = <span class="built_in">Functor</span>();</span><br><span class="line">    std::function&lt;<span class="type">int</span>(<span class="type">int</span>, <span class="type">int</span>)&gt; func3 = [](<span class="type">int</span> x, <span class="type">int</span> y) &#123; <span class="keyword">return</span> x + y; &#125;;</span><br><span class="line">    </span><br><span class="line">    std::cout &lt;&lt; <span class="built_in">func1</span>(<span class="number">3</span>, <span class="number">5</span>) &lt;&lt; std::endl; <span class="comment">// Output: 8</span></span><br><span class="line">    std::cout &lt;&lt; <span class="built_in">func2</span>(<span class="number">3</span>, <span class="number">5</span>) &lt;&lt; std::endl; <span class="comment">// Output: 8</span></span><br><span class="line">    std::cout &lt;&lt; <span class="built_in">func3</span>(<span class="number">3</span>, <span class="number">5</span>) &lt;&lt; std::endl; <span class="comment">// Output: 8</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<h2 id="空std-function"><a href="#空std-function" class="headerlink" title="空std::function"></a>空<code>std::function</code></h2><p>如果一个<code>std::function</code>没有与之关联的可调用对象，那么它被称为空的。</p>
<p>调用一个空的<code>std::function</code>会导致<code>std::bad_function_call</code>异常的抛出。</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;functional&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    std::function&lt;<span class="type">int</span>(<span class="type">int</span>, <span class="type">int</span>)&gt; func;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span> </span><br><span class="line">    &#123;</span><br><span class="line">        <span class="type">int</span> result = <span class="built_in">func</span>(<span class="number">3</span>, <span class="number">5</span>); <span class="comment">// 调用空的std::function，会抛出std::bad_function_call异常</span></span><br><span class="line">        std::cout &lt;&lt; result &lt;&lt; std::endl;</span><br><span class="line">    &#125; </span><br><span class="line">    <span class="built_in">catch</span> (<span class="type">const</span> std::bad_function_call&amp; ex) </span><br><span class="line">    &#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;Exception caught: &quot;</span> &lt;&lt; ex.<span class="built_in">what</span>() &lt;&lt; std::endl; <span class="comment">// Output: Exception caught: bad_function_call</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<h2 id="std-function与多态"><a href="#std-function与多态" class="headerlink" title="std::function与多态"></a><code>std::function</code>与多态</h2><p>由于<code>std::function</code>可以存储任意可调用对象，因此它可以用来实现多态行为。</p>
<p>这意味着可以将不同的函数对象绑定到一个<code>std::function</code>上，然后通过调用<code>std::function</code>来实现不同的行为。</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;functional&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Animal</span> </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">makeSound</span><span class="params">()</span> <span class="type">const</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Dog</span> : <span class="keyword">public</span> Animal</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">makeSound</span><span class="params">()</span> <span class="type">const</span> <span class="keyword">override</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;Woof!&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Cat</span> : <span class="keyword">public</span> Animal</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">makeSound</span><span class="params">()</span> <span class="type">const</span> <span class="keyword">override</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;Meow!&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    std::function&lt;<span class="type">void</span>(<span class="type">const</span> Animal&amp;)&gt; makeSoundFunc;</span><br><span class="line"></span><br><span class="line">    Dog dog;</span><br><span class="line">    Cat cat;</span><br><span class="line"></span><br><span class="line">    makeSoundFunc = [](<span class="type">const</span> Animal&amp; animal) &#123; animal.<span class="built_in">makeSound</span>(); &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">makeSoundFunc</span>(dog); <span class="comment">// Output: Woof!</span></span><br><span class="line">    <span class="built_in">makeSoundFunc</span>(cat); <span class="comment">// Output: Meow!</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>在上述例子中，我们使用<code>std::function</code>将不同的动物对象（<code>Dog</code>和<code>Cat</code>）的<code>makeSound()</code>方法封装起来，然后通过<code>makeSoundFunc()</code>调用不同的动物的声音输出。</p>
<p><code>std::function</code>是C++中一个非常有用的工具，特别是在需要实现多态行为或在接口设计中解耦函数的返回类型和参数类型时。</p>
<p>它使得处理函数对象变得更加灵活和通用。</p>
<h2 id="std-function与非静态成员函数"><a href="#std-function与非静态成员函数" class="headerlink" title="std::function与非静态成员函数"></a><code>std::function</code>与非静态成员函数</h2><p>类的非静态成员函数是依赖于实例化对象的，需要先创建并实例化出对象，使用<code>std::function</code>封装类的非静态成员函数有三种方法：使用lambda表达式、使用<code>std::bind</code>、直接封装。</p>
<p>下面将给出使用lambda表达式和直接封装的代码示例。</p>
<p>lambda表达式：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;functional&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyClass</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">nonStaticFunction</span><span class="params">(<span class="type">int</span> value)</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;Non-static function called with value: &quot;</span> &lt;&lt; value &lt;&lt; std::endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    MyClass obj;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 使用lambda表达式也可以将类的实例和成员函数捕获，创建一个可调用的对象</span></span><br><span class="line">    std::function&lt;<span class="type">void</span>(<span class="type">int</span>)&gt; func = [&amp;obj](<span class="type">int</span> value)&#123;obj.<span class="built_in">nonStaticFunction</span>(value);&#125;;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 现在可以像调用普通函数一样调用封装的成员函数</span></span><br><span class="line">    <span class="built_in">func</span>(<span class="number">100</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>直接封装：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;functional&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyClass</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">add</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b)</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> a + b;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    MyClass obj;</span><br><span class="line"></span><br><span class="line">    std::function&lt;<span class="type">int</span>(MyClass&amp;, <span class="type">int</span>, <span class="type">int</span>)&gt; func = &amp;MyClass::add;</span><br><span class="line">	<span class="comment">//调用</span></span><br><span class="line">    <span class="built_in">func</span>();</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>使用<code>std::bind</code>将在后续讲解。</p>
<h2 id="std-function的成员函数"><a href="#std-function的成员函数" class="headerlink" title="std::function的成员函数"></a><code>std::function</code>的成员函数</h2><p><code>std::function</code>是一个通用的函数封装器，它提供了一系列成员函数来管理和操作封装的可调用对象。</p>
<p>下面是<code>std::function</code>的一些重要成员函数及其作用：</p>
<ul>
<li><p>构造函数：</p>
<ul>
<li><code>function::function()</code>：默认构造函数，创建一个空的<code>std::function</code>对象。</li>
<li><code>function::function(nullptr_t)</code>：构造一个空的<code>std::function</code>对象。</li>
<li><code>function::function(const function&amp;)</code>：复制构造函数，用于创建一个<code>std::function</code>对象，复制另一个<code>std::function</code>对象的内容。</li>
</ul>
</li>
<li><p>赋值和重置：</p>
<ul>
<li><code>function::operator=</code>：赋值运算符，用于将一个<code>std::function</code>对象赋值给另一个。</li>
<li><code>function::operator=(nullptr_t)</code>：将<code>std::function</code>对象重置为空。</li>
</ul>
</li>
<li><p>调用和运行时类型判断：</p>
<ul>
<li><code>function::operator()</code>：函数调用运算符，用于调用封装的可调用对象。</li>
<li><code>function::target()</code>：返回指向封装的可调用对象的指针，可以用于判断其运行时类型。</li>
<li><code>function::target_type()</code>：返回封装的可调用对象的类型。</li>
</ul>
</li>
<li><p>检查是否为空：</p>
<ul>
<li><code>function::operator bool()</code>：将<code>std::function</code>对象转换为<code>bool</code>值，判断是否为空。</li>
</ul>
</li>
<li><p>交换两个对象的内容：</p>
<ul>
<li><p><code>function::swap()</code>：用于交换两个<code>std::function</code>对象的内容。</p>
<p><code>swap()</code>函数允许在不复制或移动可调用对象的情况下，高效地交换两个<code>std::function</code>对象的内容。这对于需要在运行时更改<code>std::function</code>对象的封装内容非常有用。</p>
<p><code>swap()</code>函数是无异常的 (<code>noexcept</code>)，因此它不会引发异常。这使得在涉及异常安全性的代码中使用<code>swap()</code>函数非常安全。</p>
</li>
</ul>
</li>
</ul>
<p>请注意，<code>std::function</code>的成员函数和操作符的行为会根据封装的可调用对象的类型而有所不同。</p>
<p>例如：</p>
<ul>
<li><p>如果封装的是一个函数指针，那么调用运算符的行为就类似于直接调用该函数。</p>
</li>
<li><p>如果封装的是一个函数对象，那么调用运算符将调用函数对象的<code>operator()</code>成员函数。</p>
</li>
</ul>
<p>这些成员函数使得<code>std::function</code>能够灵活地处理不同类型的可调用对象，并提供了一致的接口来管理和使用这些对象。</p>
<h1 id="std-bind"><a href="#std-bind" class="headerlink" title="std::bind"></a><code>std::bind</code></h1><h2 id="概述-1"><a href="#概述-1" class="headerlink" title="概述"></a>概述</h2><p>在C++中，<code>std::bind</code>是一个非常有用的函数模板，用于创建一个函数对象，可以将参数绑定到该对象，并延迟调用相应的函数。它的主要作用是部分应用函数参数或重新排序函数参数。<code>std::bind</code>位于<code>&lt;functional&gt;</code>头文件中，并在C++11及以上版本的标准中提供支持。</p>
<p><code>std::bind</code>的语法如下：</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">template</span>&lt; <span class="keyword">class</span> F, <span class="keyword">class</span>... Args &gt;</span></span><br><span class="line"><span class="function">std::function&lt;<span class="title">F</span><span class="params">(Args...)</span>&gt; <span class="title">bind</span><span class="params">( F&amp;&amp; f, Args&amp;&amp;... args )</span></span>;</span><br></pre></td></tr></table></figure></div>

<p><code>std::bind</code>接受一个可调用对象 <code>f</code> 和若干个参数 <code>args</code>（这些参数可以是常量、变量或者其他函数对象），返回一个新的函数对象，该函数对象可以在稍后调用，实际执行时，将会使用绑定的参数和<code>f</code>原来的参数一起传递。</p>
<h2 id="绑定自由函数"><a href="#绑定自由函数" class="headerlink" title="绑定自由函数"></a>绑定自由函数</h2><div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;functional&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">add</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b)</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> a + b;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">auto</span> func = std::<span class="built_in">bind</span>(add, <span class="number">10</span>, <span class="number">20</span>);</span><br><span class="line">    std::cout &lt;&lt; <span class="built_in">func</span>() &lt;&lt; std::endl; <span class="comment">// 输出 30</span></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>在这个例子中，我们通过<code>std::bind</code>将<code>add</code>函数的前两个参数绑定为<code>10</code>和<code>20</code>。</p>
<p>生成的<code>func</code>函数对象可以直接调用，而无需再传递<code>add</code>函数的前两个参数。</p>
<h2 id="绑定成员函数"><a href="#绑定成员函数" class="headerlink" title="绑定成员函数"></a>绑定成员函数</h2><div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;functional&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Calculator</span> </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">add</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b)</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> a + b;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    Calculator calc;</span><br><span class="line">    <span class="keyword">auto</span> func = std::<span class="built_in">bind</span>(&amp;Calculator::add, &amp;calc, <span class="number">10</span>, <span class="number">20</span>);</span><br><span class="line">    std::cout &lt;&lt; <span class="built_in">func</span>() &lt;&lt; std::endl; <span class="comment">// 输出 30</span></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>在这个例子中，我们使用<code>std::bind</code>将<code>Calculator</code>类的成员函数<code>add</code>绑定到对象<code>calc</code>上，并绑定前两个参数为<code>10</code>和<code>20</code>。</p>
<p>注意：非静态成员函数是依赖于实例化对象的。</p>
<p>生成的<code>func</code>函数对象可以直接调用，并在调用时使用绑定的对象和参数。</p>
<h2 id="占位符"><a href="#占位符" class="headerlink" title="占位符"></a>占位符</h2><p><code>std::bind</code>的占位符是一个特殊的标记，用于表示在调用绑定后的函数对象时，哪些参数需要从调用时的实际参数中获取，而哪些参数是已经绑定好的。</p>
<p>占位符以<code>std::placeholders::_N</code>的形式表示，其中<code>N</code>是一个非负整数，表示参数的位置索引。</p>
<p><code>std::placeholders::_1</code>表示第一个参数，<code>std::placeholders::_2</code>表示第二个参数，以此类推。</p>
<p>在使用<code>std::bind</code>时，可以在绑定的函数对象中使用占位符，然后在调用函数对象时，传递实际的参数来替换这些占位符，以完成参数的绑定。</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;functional&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">add</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b, <span class="type">int</span> c)</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> a + b + c;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">auto</span> func = std::<span class="built_in">bind</span>(add, std::placeholders::_2, std::placeholders::_1, std::placeholders::_3);</span><br><span class="line">    std::cout &lt;&lt; <span class="built_in">func</span>(<span class="number">10</span>, <span class="number">20</span>, <span class="number">30</span>) &lt;&lt; std::endl; <span class="comment">// 输出 60  (20 + 10 + 30)</span></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure></div>

<p>在这个例子中，我们使用<code>std::bind</code>将函数<code>add</code>的参数重新排列，通过占位符的位置调整了参数的顺序。</p>
<p><code>std::placeholders::_2</code>表示实际调用时的第二个参数，<code>std::placeholders::_1</code>表示实际调用时的第一个参数，<code>std::placeholders::_3</code>表示实际调用时的第三个参数。</p>
<p>&#x3D;&#x3D;注意：参数顺序与<code>std::placeholders::_N</code>中N的顺序是一一对应的。假如只有<code>std::placeholders::_2</code>而没有<code>std::placeholders::_1</code>，那么只传入一个参数时将会报错，传入两个参数时第一个参数将会被忽略，以此类推。&#x3D;&#x3D;</p>
<h2 id="绑定到lambda函数"><a href="#绑定到lambda函数" class="headerlink" title="绑定到lambda函数"></a>绑定到lambda函数</h2><div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;functional&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> base = <span class="number">10</span>;</span><br><span class="line">    <span class="keyword">auto</span> func = std::<span class="built_in">bind</span>([](<span class="type">int</span> x, <span class="type">int</span> y) &#123; <span class="keyword">return</span> x + y + base; &#125;, <span class="number">20</span>, std::placeholders::_1);</span><br><span class="line">    std::cout &lt;&lt; <span class="built_in">func</span>(<span class="number">30</span>) &lt;&lt; std::endl; <span class="comment">// 输出 60 (20 + 30 + 10)</span></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>在这个例子中，我们使用<code>std::bind</code>将一个Lambda函数绑定，并在绑定时指定了其中的一个参数为<code>20</code>，另一个参数使用<code>std::placeholders::_1</code>占位符，表示稍后调用<code>func</code>时传递的参数。同时，Lambda函数内部使用了外部的变量<code>base</code>，这个变量在绑定时被捕获了。</p>
<h2 id="std-bind和std-function结合使用"><a href="#std-bind和std-function结合使用" class="headerlink" title="std::bind和std::function结合使用"></a><code>std::bind</code>和<code>std::function</code>结合使用</h2><p>可以使用<code>std::function</code>来封装类中的非静态成员函数。</p>
<p>要封装类中的非静态成员函数，需要使用<code>std::bind</code>或lambda表达式，将类的实例（对象）绑定到成员函数上。</p>
<p>这样，就可以将成员函数封装成一个可调用的对象，然后再将其传递给<code>std::function</code>。</p>
<p>下面是一个示例代码，演示了如何使用<code>std::function</code>配合<code>std::bind</code>封装类中的非静态成员函数：</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;functional&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyClass</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">nonStaticFunction</span><span class="params">(<span class="type">int</span> value)</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;Non-static function called with value: &quot;</span> &lt;&lt; value &lt;&lt; std::endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    MyClass obj;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 使用std::bind将类的实例和成员函数绑定，创建一个可调用的对象</span></span><br><span class="line">    std::function&lt;<span class="type">void</span>(<span class="type">int</span>)&gt; func1 = std::<span class="built_in">bind</span>(&amp;MyClass::nonStaticFunction, &amp;obj, std::placeholders::_1);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 现在可以像调用普通函数一样调用封装的成员函数</span></span><br><span class="line">    <span class="built_in">func1</span>(<span class="number">42</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>在上面的示例中，<code>func1</code>是<code>std::function</code>类型的对象，封装了<code>MyClass</code>类的<code>nonStaticFunction</code>成员函数。</p>
<p><code>func1</code>使用<code>std::bind</code>将<code>obj</code>对象和成员函数绑定在一起。</p>
<p>请注意，在使用<code>std::bind</code>时，需要传递类实例的指针作为第一个参数，以确保成员函数能够正确访问类的实例。</p>
<p>而在使用lambda表达式时，可以通过捕获列表来捕获类实例，以便在lambda函数体内使用。</p>
<h1 id="继承构造"><a href="#继承构造" class="headerlink" title="继承构造"></a>继承构造</h1><p>在C++11中引入了继承构造特性（Inheriting Constructors），允许派生类继承基类的构造函数（默认构造函数、拷贝构造函数、移动构造函数除外）。</p>
<p>这种特性简化了代码，避免了在派生类中重新实现相同的构造函数。</p>
<p>继承构造特性通过在派生类中使用<code>using</code>声明语句来实现。</p>
<p>通过<code>using</code>声明，派生类可以直接使用基类的构造函数，而不需要重新定义或调用它们。</p>
<p>示例：</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Base</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Base</span>(<span class="type">int</span> x) </span><br><span class="line">    &#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;Base constructor called with x = &quot;</span> &lt;&lt; x &lt;&lt; std::endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Derived</span> : <span class="keyword">public</span> Base </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">using</span> Base::Base;  <span class="comment">// 继承基类的构造函数</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">DoSomething</span><span class="params">()</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;Doing something in the derived class.&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="function">Derived <span class="title">derived</span><span class="params">(<span class="number">42</span>)</span></span>;</span><br><span class="line">    derived.<span class="built_in">DoSomething</span>();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>在上面的代码中，<code>Base</code>类有一个接受一个整数参数的构造函数。</p>
<p><code>Derived</code>类通过使用<code>using Base::Base;</code>语句继承了<code>Base</code>的构造函数。</p>
<p>这意味着在创建<code>Derived</code>对象时，可以直接使用<code>Base</code>类的构造函数，并且传递相同的参数。</p>
<p>输出：</p>
<div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Base constructor called with x = 42</span><br><span class="line">Doing something in the derived class.</span><br></pre></td></tr></table></figure></div>

<p>可以看到，通过继承构造特性，<code>Derived</code>类实例化时会自动调用<code>Base</code>类的构造函数，并传递相应的参数。</p>
<p>继承构造特性还可以用于多重继承的情况，允许派生类继承多个基类的构造函数。</p>
<p>如果基类构造函数有默认参数，派生类也会继承这些默认参数。</p>
<p>继承构造特性简化了代码编写，并提高了代码的可读性和维护性。</p>
<p>注意事项：</p>
<ul>
<li><p>继承构造一般只适用于派生类中没有新增成员变量的情况下，继承构造只能初始化基类中的成员变量，不能初始化派生类中的成员变量，如果派生类新增了成员变量，那么继承构造的意义不大。</p>
</li>
<li><p>使用继承构造时，派生类不能是虚继承基类，否则编译报错。</p>
</li>
<li><p>派生类一旦使用继承构造，那么编译器不会再提供默认构造函数。</p>
</li>
<li><p>派生类只能继承可见的基类构造函数。如果基类的构造函数是私有的或受保护的，派生类无法使用继承构造特性。只有公有的基类构造函数才能被继承。</p>
</li>
<li><p>如果派生类自己定义了与基类构造函数相同的构造函数（包括参数类型和个数），那么继承构造特性将失效。派生类不会继承基类的构造函数，而是使用自己定义的构造函数。</p>
</li>
<li><p>继承构造特性会继承基类构造函数的默认参数。这意味着在派生类中，可以选择省略这些默认参数或者提供新的默认参数值。</p>
</li>
<li><p>如果派生类从多个基类继承构造函数，并且这些构造函数具有相同的签名，那么在派生类中使用继承构造特性时会引发重载解析问题。这时需要使用限定符或显式地指定所需的构造函数。</p>
</li>
<li><p>如果基类使用虚拟继承（virtual inheritance），派生类无法继承其构造函数。在这种情况下，需要在派生类中手动定义构造函数，并在初始化列表中调用基类的构造函数。</p>
</li>
</ul>
<h1 id="委托构造"><a href="#委托构造" class="headerlink" title="委托构造"></a>委托构造</h1><p>C++11引入了委托构造（Delegating Constructors）的特性，它允许一个构造函数在同一个类中调用另一个构造函数来完成对象的初始化。</p>
<p>这样可以避免在类中重复编写相似的初始化代码，提高代码的可读性和维护性。</p>
<p>在使用委托构造时，可以通过在构造函数的初始化列表中使用类似于函数调用的语法来调用其他构造函数。</p>
<p>下面是一个简单的示例代码，演示了如何使用委托构造：</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyClass</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">MyClass</span>() : <span class="built_in">MyClass</span>(<span class="number">0</span>) </span><br><span class="line">    &#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;Default constructor&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">MyClass</span>(<span class="type">int</span> x) : <span class="built_in">MyClass</span>(x, <span class="number">0</span>) </span><br><span class="line">    &#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;Constructor with one parameter: &quot;</span> &lt;&lt; x &lt;&lt; std::endl;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">MyClass</span>(<span class="type">int</span> x, <span class="type">int</span> y) : <span class="built_in">x_</span>(x), <span class="built_in">y_</span>(y) </span><br><span class="line">    &#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;Constructor with two parameters: &quot;</span> &lt;&lt; x &lt;&lt; <span class="string">&quot;, &quot;</span> &lt;&lt; y &lt;&lt; std::endl;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="type">int</span> x_;</span><br><span class="line">    <span class="type">int</span> y_;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    MyClass obj1;               <span class="comment">// 调用默认构造函数</span></span><br><span class="line">    <span class="function">MyClass <span class="title">obj2</span><span class="params">(<span class="number">42</span>)</span></span>;           <span class="comment">// 调用带一个参数的构造函数</span></span><br><span class="line">    <span class="function">MyClass <span class="title">obj3</span><span class="params">(<span class="number">10</span>, <span class="number">20</span>)</span></span>;       <span class="comment">// 调用带两个参数的构造函数</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>在上面的代码中，<code>MyClass</code>类中定义了三个构造函数。</p>
<p>默认构造函数调用了带一个参数的构造函数，带一个参数的构造函数又调用了带两个参数的构造函数。</p>
<p>这种构造函数之间的相互调用就是委托构造。</p>
<p>输出：</p>
<div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Constructor with two parameters: 0, 0</span><br><span class="line">Default constructor</span><br><span class="line">Constructor with one parameter: 42</span><br><span class="line">Constructor with two parameters: 10, 20</span><br></pre></td></tr></table></figure></div>

<p>可以看到，通过使用委托构造，不需要在每个构造函数中重复编写相同的初始化代码。</p>
<p>相反，每个构造函数只需要关注它自己特定的初始化逻辑，并将共享的初始化工作委托给其他构造函数。</p>
<p>需要注意的是，委托构造函数的调用发生在当前构造函数的初始化列表中。</p>
<p>委托构造函数必须位于当前构造函数初始化列表的最开始位置。</p>
<p>这是因为在初始化列表中的其他成员初始化之前，必须先选择正确的构造函数进行委托。</p>
<p>委托构造使得构造函数的代码更加简洁和易于维护。它是提高代码可读性和减少重复代码的有用工具。</p>
<h1 id="智能指针"><a href="#智能指针" class="headerlink" title="智能指针"></a>智能指针</h1><h2 id="智能指针的概述"><a href="#智能指针的概述" class="headerlink" title="智能指针的概述"></a>智能指针的概述</h2><hr>
<p>C++的指针包括两种：</p>
<ul>
<li>原始指针（raw pointer)</li>
<li>智能指针</li>
</ul>
<p>智能指针是原始指针的封装，其优点是会自动分配内存，不用担心潜在的内存泄露。</p>
<p>并不是所有的指针都可以封装成智能指针，很多时候原始指针要更方便。</p>
<p>C++11中通过引入智能指针的概念，使得C++程序员不需要手动释放内存。</p>
<p>智能指针的种类：</p>
<ul>
<li><p><code>std:unique_ptr</code></p>
</li>
<li><p><code>std::shared_ptr</code></p>
</li>
<li><p><code>std::weak_ptr</code></p>
</li>
<li><p><code>std::auto ptr</code>（已被废弃）</p>
</li>
</ul>
<p>各种指针中，最常用的是裸指针，其次是<code>unique _ptr</code>和<code>shared ptr</code></p>
<p><code>weak_ptr</code>是<code>shared _ptr</code>的一个补充，应用场景较少。</p>
<p>智能指针只解决一部分问题，即独占、共享、所有权、指针的释放、传输</p>
<p>智能指针没有从根本上解决C++内存安全问题，不加以注意依然会造成内存安全问题</p>
<h2 id="unique-ptr（独占指针）"><a href="#unique-ptr（独占指针）" class="headerlink" title="unique_ptr（独占指针）"></a><code>unique_ptr</code>（独占指针）</h2><hr>
<h3 id="概念和用法"><a href="#概念和用法" class="headerlink" title="概念和用法"></a>概念和用法</h3><hr>
<p><code>unique_ptr</code>是一种智能指针，用于管理动态分配的对象。</p>
<p>它提供了一种独占式所有权模式，即&#x3D;&#x3D;一个对象只能由一个<code>unique_ptr</code>拥有&#x3D;&#x3D;。</p>
<p>当<code>unique_ptr</code>被销毁或重置时，它所拥有的对象也会被销毁。</p>
<p>以下是<code>unique_ptr</code>的主要特点和用法：</p>
<ul>
<li><p><strong>头文件引入</strong>：</p>
<p><code>unique_ptr</code>位于 <code>&lt;memory&gt;</code> 头文件中，要使用它，需要包含该头文件。</p>
</li>
<li><p><strong>对象的所有权</strong>：</p>
<p><code>unique_ptr</code>通过将对象包装在一个指针内部，拥有对该对象的独占所有权。这意味着没有其他指针可以同时指向该对象。</p>
</li>
<li><p><strong>动态内存分配</strong>：</p>
<p>通常，<code>unique_ptr</code>用于管理动态分配的对象。可以使用<code>new</code>关键字来创建一个对象，并将其传递给<code>unique_ptr</code>的构造函数。</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::unique_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>)</span></span>; <span class="comment">// 创建一个动态分配的int对象</span></span><br></pre></td></tr></table></figure></div>
</li>
<li><p><strong>指针语义</strong>：</p>
<p><code>unique_ptr</code>具有与原始指针类似的语义，可以像使用原始指针一样对待它。</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">  <span class="function">std::unique_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>)</span></span>; <span class="comment">// 创建一个动态分配的int对象</span></span><br><span class="line">  *ptr = <span class="number">10</span>;      <span class="comment">// 对动态分配的对象进行赋值</span></span><br><span class="line">  <span class="type">int</span> value = *ptr; <span class="comment">// 从指针获取对象的值</span></span><br><span class="line"></span><br><span class="line">- **移动语义**：</span><br><span class="line"></span><br><span class="line">  由于`unique_ptr`拥有对象的独占所有权，因此它可以被移动，但不能被复制。</span><br><span class="line"></span><br><span class="line">  这意味着可以将`unique_ptr`转移到另一个`unique_ptr`，而原始的`unique_ptr`将失去对对象的所有权。</span><br><span class="line"></span><br><span class="line">  ```c++</span><br><span class="line">  <span class="function">std::unique_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr1</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>)</span></span>;</span><br><span class="line">  std::unique_ptr&lt;<span class="type">int</span>&gt; ptr2 = std::<span class="built_in">move</span>(ptr1); <span class="comment">// 转移ptr1的所有权给ptr2</span></span><br><span class="line"></span><br><span class="line">- **释放内存**：</span><br><span class="line"></span><br><span class="line">  当`unique_ptr`超出范围、被重置或被销毁时，它所拥有的对象会自动被销毁。</span><br><span class="line"></span><br><span class="line">  这意味着不需要手动调用`<span class="keyword">delete</span>`来释放内存，从而避免了内存泄漏。</span><br><span class="line"></span><br><span class="line">  ```c++</span><br><span class="line">  <span class="function">std::unique_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>)</span></span>;</span><br><span class="line">  <span class="comment">// ...</span></span><br><span class="line">  ptr.<span class="built_in">reset</span>(); <span class="comment">// 重置unique_ptr，对象会被销毁</span></span><br><span class="line">  <span class="comment">// unique_ptr生命周期结束对象也会被自动销毁</span></span><br></pre></td></tr></table></figure></div>
</li>
<li><p><strong>空指针检查</strong>：</p>
<p>可以使用<code>unique_ptr</code>的<code>get</code>函数来检查它是否指向一个有效的对象。</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">  std::unique_ptr&lt;<span class="type">int</span>&gt; ptr;</span><br><span class="line">  <span class="keyword">if</span> (ptr.<span class="built_in">get</span>() != <span class="literal">nullptr</span>) </span><br><span class="line">  &#123;</span><br><span class="line">      <span class="comment">// ptr指向一个有效的对象</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">- **自定义删除器**：</span><br><span class="line"></span><br><span class="line">   `unique_ptr`还可以使用自定义的删除器函数或函数对象来管理对象的销毁。</span><br><span class="line">   </span><br><span class="line">   ```cpp</span><br><span class="line">   <span class="keyword">struct</span> <span class="title class_">CustomDeleter</span> </span><br><span class="line">   &#123;</span><br><span class="line">       <span class="function"><span class="type">void</span> <span class="title">operator</span><span class="params">()</span><span class="params">(<span class="type">int</span>* ptr)</span> <span class="type">const</span> </span></span><br><span class="line"><span class="function">       </span>&#123;</span><br><span class="line">           <span class="comment">// 自定义的对象销毁操作</span></span><br><span class="line">           <span class="keyword">delete</span> ptr;</span><br><span class="line">       &#125;</span><br><span class="line">   &#125;;</span><br><span class="line">   </span><br><span class="line">   <span class="function">std::unique_ptr&lt;<span class="type">int</span>, CustomDeleter&gt; <span class="title">ptr</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>, CustomDeleter())</span></span>;</span><br><span class="line">   <span class="comment">//第二个参数即重载()的仿函数，模板参数中删除器类型必须指定，函数参数可以不指定</span></span><br><span class="line">   <span class="comment">//std::unique_ptr&lt;int, CustomDeleter&gt; ptr(new int);//这样也行，效果一样</span></span><br></pre></td></tr></table></figure></div></li>
</ul>
<p><code>unique_ptr</code>提供了一种安全且方便的方式来管理动态分配的对象，可以避免内存泄漏和手动内存管理的麻烦。</p>
<p>但需要注意的是，由于其独占性质，<code>unique_ptr</code>不适用于需要多个指针共享所有权的情况。在这种情况下，应该考虑使用<code>shared_ptr</code>智能指针。</p>
<h3 id="错误使用示例"><a href="#错误使用示例" class="headerlink" title="错误使用示例"></a>错误使用示例</h3><hr>
<p>关于<code>unique_ptr</code>的独占性，以下是一些可能导致错误的示例：</p>
<p><strong>错误示例 1：复制<code>unique_ptr</code></strong></p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::unique_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr1</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>)</span></span>;</span><br><span class="line">std::unique_ptr&lt;<span class="type">int</span>&gt; ptr2 = ptr1; <span class="comment">// 错误！不能复制unique_ptr</span></span><br></pre></td></tr></table></figure></div>

<p>由于<code>unique_ptr</code>的独占性，它不能被复制。在上面的示例中，试图将<code>ptr1</code>复制给<code>ptr2</code>将导致编译错误。</p>
<p><strong>错误示例 2：使用原始指针共享所有权</strong></p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::unique_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>)</span></span>;</span><br><span class="line"><span class="type">int</span>* rawPtr = ptr.<span class="built_in">get</span>(); <span class="comment">// 获取原始指针</span></span><br><span class="line"><span class="function">std::shared_ptr&lt;<span class="type">int</span>&gt; <span class="title">sharedPtr</span><span class="params">(rawPtr)</span></span>; <span class="comment">// 错误！不能与shared_ptr共享所有权</span></span><br></pre></td></tr></table></figure></div>

<p>由于<code>unique_ptr</code>的独占性，它不能与<code>shared_ptr</code>共享所有权。</p>
<p>在上面的示例中，将<code>unique_ptr</code>的原始指针传递给<code>shared_ptr</code>的构造函数是错误的，会导致多个智能指针同时管理同一个对象，可能引发内存释放问题。</p>
<p><strong>错误示例 3：返回局部的<code>unique_ptr</code></strong></p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::unique_ptr&lt;<span class="type">int</span>&gt; <span class="title">createPtr</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="function">std::unique_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>)</span></span>;</span><br><span class="line">    <span class="keyword">return</span> ptr; <span class="comment">// 错误！返回局部unique_ptr的所有权</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">std::unique_ptr&lt;<span class="type">int</span>&gt; ptr = <span class="built_in">createPtr</span>(); <span class="comment">// 错误！悬空指针</span></span><br></pre></td></tr></table></figure></div>

<p>在上面的示例中，<code>createPtr</code>函数试图返回一个局部创建的<code>unique_ptr</code>，这是错误的。当函数返回时，局部对象将被销毁，导致指向无效内存的悬空指针。</p>
<p><strong>错误示例 4：将相同的原始指针传递给多个<code>unique_ptr</code></strong></p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span>* rawPtr = <span class="keyword">new</span> <span class="type">int</span>;</span><br><span class="line"><span class="function">std::unique_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr1</span><span class="params">(rawPtr)</span></span>;</span><br><span class="line"><span class="function">std::unique_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr2</span><span class="params">(rawPtr)</span></span>; <span class="comment">// 错误！多个unique_ptr管理同一个原始指针</span></span><br></pre></td></tr></table></figure></div>

<p>在上面的示例中，试图将相同的原始指针传递给多个<code>unique_ptr</code>是错误的。这将导致多个智能指针同时尝试删除同一个内存块，可能导致重复释放或悬空指针。</p>
<p>需要特别注意<code>unique_ptr</code>的独占性质，并避免以上错误，以确保正确使用和管理动态分配的对象。</p>
<h3 id="成员函数详解"><a href="#成员函数详解" class="headerlink" title="成员函数详解"></a>成员函数详解</h3><hr>
<p><code>unique_ptr</code>类提供了一系列成员函数来管理和操作智能指针，以下是其中一些常用的成员函数及其作用：</p>
<ul>
<li><p>**<code>reset()</code>**：重置<code>unique_ptr</code>，释放当前拥有的对象，并接管新的对象。如果没有参数，则释放当前调用对象拥有的对象，<code>uinque_ptr</code>变为悬空指针。</p>
 <div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::unique_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>)</span></span>;</span><br><span class="line"><span class="comment">// ...</span></span><br><span class="line">ptr.<span class="built_in">reset</span>(<span class="keyword">new</span> <span class="type">int</span>); <span class="comment">// 重置unique_ptr，释放旧对象并接管新对象</span></span><br><span class="line"><span class="comment">//ptr.reset()// 释放拥有的对象，变为悬空指针</span></span><br></pre></td></tr></table></figure></div>
</li>
<li><p>**<code>release()</code>**：释放<code>unique_ptr</code>对对象的所有权，并返回指向该对象的原始指针，<code>unique_ptr</code>变为悬空指针。</p>
 <div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::unique_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>)</span></span>;</span><br><span class="line"><span class="type">int</span>* rawPtr = ptr.<span class="built_in">release</span>(); <span class="comment">// 释放unique_ptr对对象的所有权，返回原始指针</span></span><br><span class="line"><span class="comment">// ...</span></span><br><span class="line"><span class="comment">//需要手动释放rawPtr</span></span><br><span class="line"><span class="keyword">delete</span> rawPtr;</span><br></pre></td></tr></table></figure></div>
</li>
<li><p>**<code>get()</code>**：返回指向<code>unique_ptr</code>管理的对象的原始指针。</p>
 <div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::unique_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>)</span></span>;</span><br><span class="line"><span class="type">int</span>* rawPtr = ptr.<span class="built_in">get</span>(); <span class="comment">// 获取指向对象的原始指针</span></span><br></pre></td></tr></table></figure></div>
</li>
<li><p>**<code>operator*()</code>**：重载解引用操作符，返回<code>unique_ptr</code>管理对象的引用。</p>
 <div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::unique_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>)</span></span>;</span><br><span class="line">*ptr = <span class="number">42</span>; <span class="comment">// 解引用unique_ptr并赋值</span></span><br></pre></td></tr></table></figure></div>
</li>
<li><p>**<code>operator-&gt;()</code>**：重载箭头操作符，返回指向<code>unique_ptr</code>管理对象的指针。</p>
 <div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::unique_ptr&lt;std::string&gt; <span class="title">ptr</span><span class="params">(<span class="keyword">new</span> std::string(<span class="string">&quot;Hello&quot;</span>))</span></span>;</span><br><span class="line">std::cout &lt;&lt; ptr-&gt;<span class="built_in">size</span>() &lt;&lt; std::endl; <span class="comment">// 使用箭头操作符访问对象的成员函数</span></span><br></pre></td></tr></table></figure></div>
</li>
<li><p>**<code>operator bool()</code>**：将<code>unique_ptr</code>转换为布尔值，判断指针是否为空（是否指向对象）。</p>
 <div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">std::unique_ptr&lt;<span class="type">int</span>&gt; ptr;</span><br><span class="line"><span class="keyword">if</span> (ptr) </span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">// 指针不为空</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>
</li>
<li><p>**<code>operator=</code>**：重载赋值操作符，用于将一个<code>unique_ptr</code>赋值给另一个。赋值后，左侧的<code>unique_ptr</code>接管右侧的对象，并且右侧的<code>unique_ptr</code>变为悬空指针。</p>
 <div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::unique_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr1</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>)</span></span>;</span><br><span class="line">std::unique_ptr&lt;<span class="type">int</span>&gt; ptr2;</span><br><span class="line">ptr2 = std::<span class="built_in">move</span>(ptr1); <span class="comment">// 将ptr1的所有权转移给ptr2，ptr1变为悬空指针</span></span><br></pre></td></tr></table></figure></div>
</li>
<li><p>**<code>operator[]</code>**：允许使用下标操作符访问<code>unique_ptr</code>管理的数组对象。</p>
  <div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::unique_ptr&lt;<span class="type">int</span>[]&gt; <span class="title">arr</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>[<span class="number">5</span>])</span></span>;</span><br><span class="line">arr[<span class="number">0</span>] = <span class="number">1</span>; <span class="comment">// 访问数组元素</span></span><br></pre></td></tr></table></figure></div>
</li>
<li><p>**<code>swap()</code>**：交换两个<code>unique_ptr</code>对象所管理的对象。</p>
 <div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::unique_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr1</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>(<span class="number">1</span>))</span></span>;</span><br><span class="line"><span class="function">std::unique_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr2</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>(<span class="number">2</span>))</span></span>;</span><br><span class="line">ptr1.<span class="built_in">swap</span>(ptr2); <span class="comment">// 交换ptr1和ptr2的对象</span></span><br></pre></td></tr></table></figure></div>
</li>
<li><p>**<code>get_deleter()</code>**：获取<code>unique_ptr</code>中自定义的删除器函数或函数对象。</p>
 <div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;memory&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">Deleter</span> </span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">operator</span><span class="params">()</span><span class="params">(<span class="type">int</span>* ptr)</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;自定义删除器 &quot;</span>&lt;&lt; std::endl;</span><br><span class="line">        <span class="keyword">delete</span> ptr;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="type">int</span>* rawPtr = <span class="keyword">new</span> <span class="built_in">int</span>(<span class="number">99</span>);</span><br><span class="line">        <span class="function">std::unique_ptr&lt;<span class="type">int</span>, Deleter&gt; <span class="title">uniquePtr</span><span class="params">(rawPtr, Deleter())</span></span>;</span><br><span class="line">        <span class="comment">//std::unique_ptr&lt;int, Deleter&gt; uniquePtr(rawPtr);//第二个函数参数可以省略</span></span><br><span class="line">        uniquePtr.<span class="built_in">get_deleter</span>()(<span class="keyword">new</span> <span class="built_in">int</span>(<span class="number">0</span>));</span><br><span class="line">    &#125;</span><br><span class="line"><span class="comment">//输出：</span></span><br><span class="line">    <span class="comment">//自定义删除器</span></span><br><span class="line">    <span class="comment">//自定义删除器</span></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div></li>
</ul>
<h3 id="使用make-unique创建和初始化"><a href="#使用make-unique创建和初始化" class="headerlink" title="使用make_unique创建和初始化"></a>使用<code>make_unique</code>创建和初始化</h3><hr>
<p><code>std::make_unique</code>是C++14中引入的一个辅助函数模板，用于创建和初始化<code>std::unique_ptr</code>对象，以更方便地进行动态内存分配和对象构造。</p>
<p>它接受类型<code>T</code>和可变数量的参数<code>Args</code>，并返回一个<code>std::unique_ptr&lt;T&gt;</code>对象。</p>
<p>使用<code>std::make_unique</code>的主要优势是它将动态内存分配和对象构造组合在一起，使代码更简洁、更安全。</p>
<p>&#x3D;&#x3D;它避免了直接使用<code>new</code>运算符来手动创建<code>unique_ptr</code>对象&#x3D;&#x3D;，并确保在发生异常时能够正确地销毁已分配的内存。</p>
<p>以下是使用<code>std::make_unique</code>的示例：</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;memory&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">MyClass</span> </span><br><span class="line">&#123;</span><br><span class="line">    <span class="built_in">MyClass</span>(<span class="type">int</span> a, <span class="type">double</span> b) </span><br><span class="line">    &#123;</span><br><span class="line">        <span class="comment">// 对象的构造逻辑</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    std::unique_ptr&lt;MyClass&gt; ptr = std::<span class="built_in">make_unique</span>&lt;MyClass&gt;(<span class="number">42</span>, <span class="number">3.14</span>);</span><br><span class="line">    <span class="comment">// 使用make_unique创建unique_ptr，并传递构造参数</span></span><br><span class="line">    <span class="comment">// 在此示例中，将调用MyClass的构造函数</span></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>在上面的示例中，<code>std::make_unique</code>用于创建一个<code>std::unique_ptr&lt;MyClass&gt;</code>对象，并传递构造参数<code>42</code>和<code>3.14</code>给<code>MyClass</code>的构造函数。</p>
<p>这样，通过<code>make_unique</code>可以在一行代码中完成对象的动态分配和构造。</p>
<p>需要注意的是，<code>std::make_unique</code>在C++14中引入，因此如果使用较旧的C++标准（如C++11或更早），则无法直接使用该函数模板。</p>
<p>在这种情况下，可以通过编写自定义的辅助函数来模拟<code>std::make_unique</code>的行为。</p>
<h2 id="shared-ptr（共享指针）"><a href="#shared-ptr（共享指针）" class="headerlink" title="shared_ptr（共享指针）"></a><code>shared_ptr</code>（共享指针）</h2><hr>
<h3 id="概念和用法-1"><a href="#概念和用法-1" class="headerlink" title="概念和用法"></a>概念和用法</h3><hr>
<p><code>shared_ptr</code>是一种智能指针，用于管理动态分配的对象。</p>
<p>与<code>unique_ptr</code>不同，<code>shared_ptr</code>实现了共享所有权的语义，允许多个智能指针共同管理同一个对象。</p>
<p>它通过使用引用计数来跟踪对象的所有权，确保对象在没有引用时被正确释放。</p>
<p>以下是<code>shared_ptr</code>的主要特点和用法：</p>
<ul>
<li><p><strong>头文件引入</strong>：</p>
<p> <code>shared_ptr</code>位于 <code>&lt;memory&gt;</code> 头文件中，因此要使用它，需要包含该头文件。</p>
</li>
<li><p><strong>对象的共享所有权</strong>：</p>
<p> <code>shared_ptr</code>通过在内部维护一个引用计数，允许多个智能指针共享对同一对象的所有权。</p>
 <div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::shared_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr1</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>)</span></span>;</span><br><span class="line">std::shared_ptr&lt;<span class="type">int</span>&gt; ptr2 = ptr1; <span class="comment">// 共享ptr1对对象的所有权</span></span><br></pre></td></tr></table></figure></div>
</li>
<li><p><strong>动态内存分配</strong>：</p>
<p> 通常，<code>shared_ptr</code>用于管理动态分配的对象。可以使用<code>new</code>关键字来创建一个对象，并将其传递给<code>shared_ptr</code>的构造函数。</p>
 <div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::shared_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>)</span></span>; <span class="comment">// 创建一个动态分配的int对象</span></span><br></pre></td></tr></table></figure></div>
</li>
<li><p><strong>引用计数</strong>：</p>
<p> <code>shared_ptr</code>内部维护了一个引用计数，跟踪有多少个<code>shared_ptr</code>实例共享同一个对象。</p>
<p> 每当创建或复制一个<code>shared_ptr</code>时，引用计数会增加。当<code>shared_ptr</code>被销毁或重置时，引用计数会减少。</p>
<p> 如果有多个<code>shard_ptr</code>共享同一个对象，当销毁或释放其中一个<code>shard_ptr</code>时，只是将这个<code>shard_ptr</code>和其所管理的内存空间解除绑定，使这个被销毁的<code>shard_ptr</code>无法再操纵原先的堆区空间（<code>shard_ptr</code>置空），并且将计数器减一，但是其他未被销毁的<code>shard_ptr</code>仍然可以操纵堆区内存。</p>
<p> 当引用计数为零时，对象会被自动销毁。</p>
</li>
<li><p><strong>拷贝和移动语义</strong>：</p>
<p> <code>shared_ptr</code>可以通过拷贝构造函数和拷贝赋值运算符进行复制。</p>
<p> 每个<code>shared_ptr</code>实例都会增加引用计数。同时，它也支持移动语义，允许通过移动构造函数和移动赋值运算符将对象的所有权转移到另一个<code>shared_ptr</code>。</p>
 <div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::shared_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr1</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>)</span></span>;</span><br><span class="line">std::shared_ptr&lt;<span class="type">int</span>&gt; ptr2 = ptr1;   <span class="comment">// 拷贝，引用计数增加</span></span><br><span class="line">std::shared_ptr&lt;<span class="type">int</span>&gt; ptr3 = std::<span class="built_in">move</span>(ptr1); <span class="comment">// 移动，ptr1的所有权转移到ptr3，ptr1变为空指针</span></span><br></pre></td></tr></table></figure></div>
</li>
<li><p><strong>循环引用问题</strong>：</p>
<p> 由于<code>shared_ptr</code>的引用计数机制，当存在循环引用时，对象可能不会被正确释放，导致内存泄漏。</p>
<p> 为了解决这个问题，C++11引入了<code>weak_ptr</code>作为<code>shared_ptr</code>的补充，用于解决循环引用的管理问题。</p>
<p> 关于循环引用将在下一节讲解。这里可以只做了解。</p>
 <div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::shared_ptr&lt;A&gt; <span class="title">ptrA</span><span class="params">(<span class="keyword">new</span> A)</span></span>;</span><br><span class="line"><span class="function">std::shared_ptr&lt;B&gt; <span class="title">ptrB</span><span class="params">(<span class="keyword">new</span> B)</span></span>;</span><br><span class="line">ptrA-&gt;b = ptrB; <span class="comment">// 假设A中有一个成员指向B</span></span><br><span class="line">ptrB-&gt;a = ptrA; <span class="comment">// 假设B中有一个成员指向A</span></span><br><span class="line">				<span class="comment">// 循环引用，可能导致对象无法正确释放</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用weak_ptr解决循环引用</span></span><br><span class="line"><span class="function">std::shared_ptr&lt;A&gt; <span class="title">ptrA</span><span class="params">(<span class="keyword">new</span> A)</span></span>;</span><br><span class="line"><span class="function">std::shared_ptr&lt;B&gt; <span class="title">ptrB</span><span class="params">(<span class="keyword">new</span> B)</span></span>;</span><br><span class="line">ptrA-&gt;b = std::<span class="built_in">weak_ptr</span>&lt;B&gt;(ptrB);</span><br><span class="line">ptrB-&gt;a = std::<span class="built_in">weak_ptr</span>&lt;A&gt;(ptrA);</span><br></pre></td></tr></table></figure></div>
</li>
<li><p><strong>自定义删除器</strong>：</p>
<p> <code>shared_ptr</code>也可以使用自定义的删除器函数或函数对象来管理对象的销毁，类似于<code>unique_ptr</code>。</p>
 <div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">struct</span> <span class="title class_">CustomDeleter</span> </span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">operator</span><span class="params">()</span><span class="params">(<span class="type">int</span>* ptr)</span> <span class="type">const</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="comment">// 自定义的对象销毁操作</span></span><br><span class="line">        <span class="keyword">delete</span> ptr;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function">std::shared_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>, CustomDeleter())</span></span>;</span><br></pre></td></tr></table></figure></div></li>
</ul>
<p><code>shared_ptr</code>提供了一种灵活的方式来管理动态分配的对象，允许多个指针共享对同一对象的所有权。</p>
<p>需要注意循环引用问题，并根据具体的使用场景选择合适的智能指针类型。</p>
<h3 id="错误使用示例-1"><a href="#错误使用示例-1" class="headerlink" title="错误使用示例"></a>错误使用示例</h3><hr>
<p>当涉及到<code>shared_ptr</code>的使用时，以下是一些可能导致错误的示例：</p>
<p><strong>错误示例 1：使用原始指针删除对象</strong></p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span>* rawPtr = <span class="keyword">new</span> <span class="type">int</span>;</span><br><span class="line"><span class="function">std::shared_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr</span><span class="params">(rawPtr)</span></span>;</span><br><span class="line"><span class="keyword">delete</span> rawPtr; <span class="comment">// 错误！不应该直接删除由shared_ptr管理的对象</span></span><br></pre></td></tr></table></figure></div>

<p>由于<code>shared_ptr</code>负责管理对象的内存，因此不应该直接使用<code>delete</code>来删除由<code>shared_ptr</code>管理的对象。在上面的示例中，试图通过<code>delete</code>关键字删除原始指针，这将导致<code>shared_ptr</code>尝试删除一个无效的指针，可能引发未定义行为。</p>
<p><strong>错误示例 2：使用<code>shared_ptr</code>管理静态对象或栈上对象</strong></p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> value = <span class="number">42</span>;</span><br><span class="line"><span class="function">std::shared_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr</span><span class="params">(&amp;value)</span></span>; <span class="comment">// 错误！不应该使用shared_ptr管理静态或栈上对象</span></span><br></pre></td></tr></table></figure></div>

<p><code>shared_ptr</code>应该用于管理动态分配的对象，而不是静态对象或栈上对象。</p>
<p>在上面的示例中，试图将一个指向静态对象的指针传递给<code>shared_ptr</code>的构造函数是错误的。</p>
<p><strong>错误示例 3：使用裸指针与<code>shared_ptr</code>共享所有权</strong></p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span>* rawPtr = <span class="keyword">new</span> <span class="type">int</span>;</span><br><span class="line"><span class="function">std::shared_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr1</span><span class="params">(rawPtr)</span></span>;</span><br><span class="line"><span class="function">std::shared_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr2</span><span class="params">(rawPtr)</span></span>; <span class="comment">// 错误！不能与shared_ptr共享同一个原始指针</span></span><br></pre></td></tr></table></figure></div>

<p>由于<code>shared_ptr</code>采用共享所有权的模式，它不适用于与其他<code>shared_ptr</code>或<code>weak_ptr</code>共享同一个原始指针。</p>
<p>这段代码是错误的，因为它试图将同一个原始指针 <code>rawPtr</code> 传递给两个独立的 <code>shared_ptr</code> 对象 <code>ptr1</code> 和 <code>ptr2</code>。这会导致引用计数错误，可能导致多次释放同一内存块，从而引发未定义行为。</p>
<p>将同一个原始指针直接传递给多个 <code>shared_ptr</code> 对象是错误的，会导致引用计数错误。</p>
<p>正确的方式是通过拷贝构造函数或拷贝赋值运算符从一个 <code>shared_ptr</code> 获得原始指针的所有权，并确保它们共享同一个对象的引用计数。</p>
<p><strong>错误示例 4：循环引用导致内存泄漏</strong></p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Node</span> </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    std::shared_ptr&lt;Node&gt; next;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function">std::shared_ptr&lt;Node&gt; <span class="title">node1</span><span class="params">(<span class="keyword">new</span> Node)</span></span>;</span><br><span class="line"><span class="function">std::shared_ptr&lt;Node&gt; <span class="title">node2</span><span class="params">(<span class="keyword">new</span> Node)</span></span>;</span><br><span class="line">node1-&gt;next = node2;</span><br><span class="line">node2-&gt;next = node1; <span class="comment">// 错误！循环引用导致对象无法正确释放</span></span><br></pre></td></tr></table></figure></div>

<p>当存在循环引用时，对象无法被正确释放，导致内存泄漏。</p>
<p>在上面的示例中，<code>node1</code>和<code>node2</code>之间形成了循环引用，它们相互持有对方的<code>shared_ptr</code>，当<code>node1</code>生命周期结束时会进行释放，但是内部有一个<code>shared_ptr</code>的智能指针于是就要释放这个智能指针，这个智能指针指向是<code>node2</code>，于是就要释放<code>node2</code>，但是<code>node2</code>内部的<code>shared_ptr</code>的智能指针又指向<code>node1</code>，于是又要释放<code>node1</code>，如此形成闭环，导致对象无法正确释放。</p>
<h3 id="成员函数详解-1"><a href="#成员函数详解-1" class="headerlink" title="成员函数详解"></a>成员函数详解</h3><hr>
<p><code>shared_ptr</code>类提供了一系列成员函数来管理和操作智能指针，以下是它的常用成员函数及其作用：</p>
<ul>
<li><p>**<code>reset()</code>**：重置<code>shared_ptr</code>，释放当前拥有的对象，并接管新的对象。</p>
 <div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::shared_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>)</span></span>;</span><br><span class="line"><span class="comment">// ...</span></span><br><span class="line">ptr.<span class="built_in">reset</span>(<span class="keyword">new</span> <span class="type">int</span>); <span class="comment">// 重置shared_ptr，释放旧对象并接管新对象</span></span><br></pre></td></tr></table></figure></div>
</li>
<li><p>**<code>get()</code>**：返回指向<code>shared_ptr</code>管理的对象的原始指针。</p>
 <div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::shared_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>)</span></span>;</span><br><span class="line"><span class="type">int</span>* rawPtr = ptr.<span class="built_in">get</span>(); <span class="comment">// 获取指向对象的原始指针</span></span><br></pre></td></tr></table></figure></div>
</li>
<li><p>**<code>use_count()</code>**：返回当前<code>shared_ptr</code>对象所管理对象的引用计数，即共享该对象的智能指针的数量。</p>
 <div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::shared_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr1</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>)</span></span>;</span><br><span class="line">std::shared_ptr&lt;<span class="type">int</span>&gt; ptr2 = ptr1;</span><br><span class="line"><span class="type">int</span> count = ptr1.<span class="built_in">use_count</span>(); <span class="comment">// 获取引用计数，值为2</span></span><br></pre></td></tr></table></figure></div>
</li>
<li><p>**<code>unique()</code>**：检查当前<code>shared_ptr</code>是否是唯一的（引用计数为1），即没有其他智能指针与之共享对象。</p>
 <div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::shared_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr1</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>)</span></span>;</span><br><span class="line">std::shared_ptr&lt;<span class="type">int</span>&gt; ptr2 = ptr1;</span><br><span class="line"><span class="keyword">if</span> (ptr1.<span class="built_in">unique</span>()) </span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">// ptr1是唯一的智能指针</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>
</li>
<li><p>**<code>operator*()</code>**：重载解引用操作符，返回<code>shared_ptr</code>管理对象的引用。</p>
 <div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::shared_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>)</span></span>;</span><br><span class="line">*ptr = <span class="number">42</span>; <span class="comment">// 解引用shared_ptr并赋值</span></span><br></pre></td></tr></table></figure></div>
</li>
<li><p>**<code>operator-&gt;()</code>**：重载箭头操作符，返回指向<code>shared_ptr</code>管理对象的指针。</p>
 <div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::shared_ptr&lt;std::string&gt; <span class="title">ptr</span><span class="params">(<span class="keyword">new</span> std::string(<span class="string">&quot;Hello&quot;</span>))</span></span>;</span><br><span class="line">std::cout &lt;&lt; ptr-&gt;<span class="built_in">size</span>() &lt;&lt; std::endl; <span class="comment">// 使用箭头操作符访问对象的成员函数</span></span><br></pre></td></tr></table></figure></div>
</li>
<li><p>**<code>operator bool()</code>**：将<code>shared_ptr</code>转换为布尔值，判断指针是否为空（是否指向对象）。</p>
 <div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">std::shared_ptr&lt;<span class="type">int</span>&gt; ptr;</span><br><span class="line"><span class="keyword">if</span> (ptr) </span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">// 指针不为空</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>
</li>
<li><p>**<code>swap()</code>**：交换两个<code>shared_ptr</code>对象所管理的对象。</p>
 <div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::shared_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr1</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>(<span class="number">1</span>))</span></span>;</span><br><span class="line"><span class="function">std::shared_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr2</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>(<span class="number">2</span>))</span></span>;</span><br><span class="line">ptr1.<span class="built_in">swap</span>(ptr2); <span class="comment">// 交换ptr1和ptr2的对象</span></span><br></pre></td></tr></table></figure></div>
</li>
<li><p>**<code>operator=</code>**：重载赋值操作符，用于将一个<code>shared_ptr</code>赋值给另一个。赋值后，左侧的<code>shared_ptr</code>接管右侧的对象，并且引用计数增加。</p>
 <div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::shared_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr1</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>)</span></span>;</span><br><span class="line">std::shared_ptr&lt;<span class="type">int</span>&gt; ptr2;</span><br><span class="line">ptr2 = ptr1; <span class="comment">// 将ptr1的对象所有权转移给ptr2，并增加引用计数</span></span><br></pre></td></tr></table></figure></div>
</li>
<li><p>**<code>owner_before()</code>**：比较两个<code>shared_ptr</code>对象的所有权关系，用于确定它们在所有权层级中的位置。</p>
  <div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::shared_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr1</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>)</span></span>;</span><br><span class="line"><span class="function">std::shared_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr2</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>)</span></span>;</span><br><span class="line"><span class="keyword">if</span> (ptr1.<span class="built_in">owner_before</span>(ptr2)) </span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">// ptr1在ptr2之前（所有权层级中）</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>
</li>
<li><p><strong><code>reset()</code>（重载版本）</strong>：重置<code>shared_ptr</code>，释放当前拥有的对象，并接管新的对象，并使用自定义删除器。</p>
  <div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">struct</span> <span class="title class_">CustomDeleter</span> </span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">operator</span><span class="params">()</span><span class="params">(<span class="type">int</span>* ptr)</span> <span class="type">const</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="comment">// 自定义的对象销毁操作</span></span><br><span class="line">        <span class="keyword">delete</span> ptr;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function">std::shared_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>, CustomDeleter())</span></span>;</span><br><span class="line"><span class="comment">// ...</span></span><br><span class="line">ptr.<span class="built_in">reset</span>(<span class="keyword">new</span> <span class="type">int</span>, <span class="built_in">CustomDeleter</span>()); <span class="comment">// 重置shared_ptr，释放旧对象并接管新对象</span></span><br></pre></td></tr></table></figure></div></li>
</ul>
<h3 id="使用make-shared创建和初始化"><a href="#使用make-shared创建和初始化" class="headerlink" title="使用make_shared创建和初始化"></a>使用<code>make_shared</code>创建和初始化</h3><p>**<code>make_shared()</code>**：创建一个包含动态分配对象的<code>shared_ptr</code>，并在分配期间同时构造对象。</p>
<p>使用方式与<code>make_unique</code>几乎一样详细参考上节使用《<code>make_unique</code>创建和初始化》的详解。</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">std::shared_ptr&lt;<span class="type">int</span>&gt; ptr = std::<span class="built_in">make_shared</span>&lt;<span class="type">int</span>&gt;(<span class="number">42</span>);</span><br><span class="line"><span class="comment">// 使用make_shared创建shared_ptr，并传递构造参数</span></span><br></pre></td></tr></table></figure></div>

<h3 id="enable-shared-from-this"><a href="#enable-shared-from-this" class="headerlink" title="enable_shared_from_this"></a><code>enable_shared_from_this</code></h3><p><code>std::enable_shared_from_this</code>是一个模板类，定义在<code>&lt;memory&gt;</code>头文件中，它是为了支持在已由<code>std::shared_ptr</code>管理的对象内部安全地获取指向自身的<code>std::shared_ptr</code>而设计的。</p>
<p>为什么要使用<code>enable_shared_from_this</code>:</p>
<ul>
<li><p>在已由<code>std::shared_ptr</code>管理的对象内部安全地获取指向自身的<code>std::shared_ptr</code>，它允许对象自己管理其共享所有权。</p>
</li>
<li><p>共享所有权：当一个对象需要与其他对象共享所有权时，可以使用<code>std::shared_ptr</code>来管理它们之间的关系。通过使用<code>std::enable_shared_from_this</code>，对象可以方便地获取指向自身的共享指针，并与其他对象共享所有权，从而确保对象在使用期间保持有效，直到没有任何共享指针引用它时才会被销毁。</p>
</li>
<li><p>回调函数：在某些情况下，对象可能需要注册回调函数，并在特定事件发生时调用这些回调函数。</p>
<p>使用<code>std::enable_shared_from_this</code>可以安全地将对象自身作为回调函数的参数传递，以避免对象在回调函数执行期间被意外销毁。</p>
</li>
<li><p>继承关系：当存在基类和派生类的继承关系时，派生类可以继承<code>std::enable_shared_from_this</code>，以便获取指向自身的共享指针。</p>
<p>这对于在派生类中访问基类成员或在派生类之间建立共享关系非常有用。</p>
</li>
</ul>
<p>使用<code>std::enable_shared_from_this</code>需要遵循以下几个步骤：</p>
<ul>
<li><p>创建一个类并公开继承自<code>std::enable_shared_from_this</code>模板类，将该类作为<code>std::shared_ptr</code>所管理的对象。</p>
</li>
<li><p>在类中添加需要使用<code>std::shared_ptr</code>的成员函数，这些函数将内部调用<code>shared_from_this()</code>函数来获取指向自身的<code>std::shared_ptr</code>。</p>
</li>
</ul>
<p>示例代码：</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;memory&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyClass</span> : <span class="keyword">public</span> std::enable_shared_from_this&lt;MyClass&gt; </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">std::shared_ptr&lt;MyClass&gt; <span class="title">getSharedPointer</span><span class="params">()</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">shared_from_this</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    std::shared_ptr&lt;MyClass&gt; ptr1 = std::<span class="built_in">make_shared</span>&lt;MyClass&gt;();</span><br><span class="line">    std::shared_ptr&lt;MyClass&gt; ptr2 = ptr1-&gt;<span class="built_in">getSharedPointer</span>();</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// ptr1和ptr2指向同一个对象</span></span><br><span class="line">    <span class="keyword">if</span> (ptr1 == ptr2) </span><br><span class="line">    &#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;ptr1 and ptr2 point to the same object.&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>在上述示例中，<code>MyClass</code>公开继承自<code>std::enable_shared_from_this&lt;MyClass&gt;</code>，并定义了<code>getSharedPointer()</code>成员函数。</p>
<p>在<code>getSharedPointer()</code>函数内部，我们调用了<code>shared_from_this()</code>函数，该函数将返回一个指向当前对象的<code>std::shared_ptr</code>。</p>
<p>在<code>main()</code>函数中，我们首先创建了一个<code>std::shared_ptr</code>指向<code>MyClass</code>的对象<code>ptr1</code>，然后通过调用<code>ptr1-&gt;getSharedPointer()</code>获取了另一个指向相同对象的<code>std::shared_ptr</code>，即<code>ptr2</code>。由于使用了<code>shared_from_this()</code>，<code>ptr1</code>和<code>ptr2</code>指向的是同一个对象，它们共享对象的所有权。</p>
<p>需要注意的是，<code>shared_from_this()</code>只能在已由<code>std::shared_ptr</code>管理的对象内部调用，否则行为是未定义的。</p>
<p>此外，为了安全使用<code>shared_from_this()</code>，必须确保在调用该函数之前已经创建了有效的<code>std::shared_ptr</code>对象来管理当前对象，否则会导致悬空指针问题。</p>
<h2 id="weak-ptr"><a href="#weak-ptr" class="headerlink" title="weak_ptr"></a><code>weak_ptr</code></h2><h3 id="概念和用法-2"><a href="#概念和用法-2" class="headerlink" title="概念和用法"></a>概念和用法</h3><p><code>weak_ptr</code>是一种智能指针，用于解决循环引用的问题。（关于循环引用参考上一节的《错误使用示例》中的”错误示例4“）</p>
<p>循环引用是指两个或多个对象彼此保持对方的引用，导致它们无法被正常地销毁。</p>
<p><code>weak_ptr</code>允许创建一个非拥有（non-owning）的指针，它可以观察和访问对象，但不会增加其引用计数。</p>
<p>当被观察的对象被销毁时，<code>weak_ptr</code>会自动变为<code>nullptr</code>，从而避免悬挂指针（dangling pointer）的问题。</p>
<p><code>weak_ptr</code>通常与<code>shared_ptr</code>一起使用。</p>
<p><code>weak_ptr</code>可以从<code>shared_ptr</code>创建，但不会增加引用计数。</p>
<p>这样，即使存在循环引用，当所有的<code>shared_ptr</code>都释放了对对象的拥有权后，对象也能被正确地销毁。</p>
<p>下面是一个简单的示例代码，演示了如何使用<code>weak_ptr</code>：</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;memory&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyClass</span> </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    std::weak_ptr&lt;MyClass&gt; otherPtr;</span><br><span class="line"></span><br><span class="line">    ~<span class="built_in">MyClass</span>() </span><br><span class="line">    &#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;MyClass destroyed&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    std::shared_ptr&lt;MyClass&gt; sharedPtr1 = std::<span class="built_in">make_shared</span>&lt;MyClass&gt;();</span><br><span class="line">    std::shared_ptr&lt;MyClass&gt; sharedPtr2 = std::<span class="built_in">make_shared</span>&lt;MyClass&gt;();</span><br><span class="line"></span><br><span class="line">    sharedPtr1-&gt;otherPtr = sharedPtr2;</span><br><span class="line">    sharedPtr2-&gt;otherPtr = sharedPtr1;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 释放sharedPtr1和sharedPtr2的拥有权</span></span><br><span class="line">    sharedPtr1.<span class="built_in">reset</span>();</span><br><span class="line">    sharedPtr2.<span class="built_in">reset</span>();</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 在上面的reset操作后，循环引用被解除，两个MyClass对象都被销毁</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>在上面的示例中，我们创建了两个<code>shared_ptr</code>对象<code>sharedPtr1</code>和<code>sharedPtr2</code>，并将它们的<code>otherPtr</code>成员变量设置为彼此。这样就形成了一个循环引用。</p>
<p>然后，我们通过调用<code>reset()</code>方法释放了<code>sharedPtr1</code>和<code>sharedPtr2</code>的拥有权。</p>
<p>由于这是最后一次拥有对这两个对象的引用，释放之后的引用计数变为0，<code>shared_ptr</code>会自动销毁这两个对象。</p>
<p>使用<code>weak_ptr</code>可以避免悬挂指针的问题，因为在对象被销毁后，<code>weak_ptr</code>会自动变为<code>nullptr</code>。</p>
<h3 id="成员函数详解-2"><a href="#成员函数详解-2" class="headerlink" title="成员函数详解"></a>成员函数详解</h3><hr>
<ul>
<li><p>**<code>expired()</code>**：用于检查<code>weak_ptr</code>是否失效，即指向的对象是否已经被销毁。如果<code>weak_ptr</code>指向的对象已经销毁，则返回<code>true</code>；否则返回<code>false</code>。</p>
<p>示例代码：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">std::shared_ptr&lt;<span class="type">int</span>&gt; sharedPtr = std::<span class="built_in">make_shared</span>&lt;<span class="type">int</span>&gt;(<span class="number">42</span>);</span><br><span class="line">std::weak_ptr&lt;<span class="type">int</span>&gt; weakPtr = sharedPtr;</span><br><span class="line"></span><br><span class="line">sharedPtr.<span class="built_in">reset</span>(); <span class="comment">// 销毁sharedPtr所拥有的对象</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (weakPtr.<span class="built_in">expired</span>()) </span><br><span class="line">&#123;</span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;weakPtr is expired&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>
</li>
<li><p>**<code>lock()</code>**：用于获取一个指向<code>weak_ptr</code>所指向对象的<code>shared_ptr</code>，如果<code>weak_ptr</code>已经失效，则返回一个空的<code>shared_ptr</code>（即<code>nullptr</code>）。</p>
<p>示例代码：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">std::shared_ptr&lt;<span class="type">int</span>&gt; sharedPtr = std::<span class="built_in">make_shared</span>&lt;<span class="type">int</span>&gt;(<span class="number">42</span>);</span><br><span class="line">std::weak_ptr&lt;<span class="type">int</span>&gt; weakPtr = sharedPtr;</span><br><span class="line"></span><br><span class="line">sharedPtr.<span class="built_in">reset</span>(); <span class="comment">// 销毁sharedPtr所拥有的对象</span></span><br><span class="line"></span><br><span class="line">std::shared_ptr&lt;<span class="type">int</span>&gt; lockedPtr = weakPtr.<span class="built_in">lock</span>();</span><br><span class="line"><span class="keyword">if</span> (lockedPtr) </span><br><span class="line">&#123;</span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;Value: &quot;</span> &lt;&lt; *lockedPtr &lt;&lt; std::endl;</span><br><span class="line">&#125; </span><br><span class="line"><span class="keyword">else</span> </span><br><span class="line">&#123;</span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;weakPtr is expired&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>
</li>
<li><p>**<code>use_count()</code>**：返回与<code>weak_ptr</code>共享对象的<code>shared_ptr</code>的引用计数。如果<code>weak_ptr</code>已经失效，则返回0。</p>
<p>示例代码：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">std::shared_ptr&lt;<span class="type">int</span>&gt; sharedPtr = std::<span class="built_in">make_shared</span>&lt;<span class="type">int</span>&gt;(<span class="number">42</span>);</span><br><span class="line">std::weak_ptr&lt;<span class="type">int</span>&gt; weakPtr = sharedPtr;</span><br><span class="line"></span><br><span class="line">std::cout &lt;&lt; <span class="string">&quot;sharedPtr use count: &quot;</span> &lt;&lt; sharedPtr.<span class="built_in">use_count</span>() &lt;&lt; std::endl;</span><br><span class="line">std::cout &lt;&lt; <span class="string">&quot;weakPtr use count: &quot;</span> &lt;&lt; weakPtr.<span class="built_in">use_count</span>() &lt;&lt; std::endl;</span><br><span class="line"></span><br><span class="line">std::shared_ptr&lt;<span class="type">int</span>&gt; lockedPtr = weakPtr.<span class="built_in">lock</span>();</span><br><span class="line"></span><br><span class="line">std::cout &lt;&lt; <span class="string">&quot;sharedPtr use count: &quot;</span> &lt;&lt; sharedPtr.<span class="built_in">use_count</span>() &lt;&lt; std::endl;</span><br><span class="line">std::cout &lt;&lt; <span class="string">&quot;weakPtr use count: &quot;</span> &lt;&lt; weakPtr.<span class="built_in">use_count</span>() &lt;&lt; std::endl;</span><br></pre></td></tr></table></figure></div>
</li>
<li><p>**<code>reset()</code>**：将<code>weak_ptr</code>置为空，不再指向任何对象。</p>
<p>示例代码：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">std::shared_ptr&lt;<span class="type">int</span>&gt; sharedPtr = std::<span class="built_in">make_shared</span>&lt;<span class="type">int</span>&gt;(<span class="number">42</span>);</span><br><span class="line">std::weak_ptr&lt;<span class="type">int</span>&gt; weakPtr = sharedPtr;</span><br><span class="line"></span><br><span class="line">std::cout &lt;&lt; <span class="string">&quot;weakPtr expired? &quot;</span> &lt;&lt; weakPtr.<span class="built_in">expired</span>() &lt;&lt; std::endl;</span><br><span class="line"></span><br><span class="line">weakPtr.<span class="built_in">reset</span>();</span><br><span class="line"></span><br><span class="line">std::cout &lt;&lt; <span class="string">&quot;weakPtr expired? &quot;</span> &lt;&lt; weakPtr.<span class="built_in">expired</span>() &lt;&lt; std::endl;</span><br></pre></td></tr></table></figure></div>

</li>
<li><p>**<code>owner_before()</code>**：比较两个<code>weak_ptr</code>对象所指向的对象所有权的相对顺序。如果当前<code>weak_ptr</code>对象的所指向对象的所有权在另一个<code>weak_ptr</code>对象之前，则返回<code>true</code>；否则返回<code>false</code>。</p>
<p>该函数用于定义<code>weak_ptr</code>对象的排序关系，例如在关联容器（如<code>std::map</code>、<code>std::set</code>）中使用。</p>
<p>示例代码：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">std::shared_ptr&lt;<span class="type">int</span>&gt; sharedPtr1 = std::<span class="built_in">make_shared</span>&lt;<span class="type">int</span>&gt;(<span class="number">42</span>);</span><br><span class="line">std::shared_ptr&lt;<span class="type">int</span>&gt; sharedPtr2 = std::<span class="built_in">make_shared</span>&lt;<span class="type">int</span>&gt;(<span class="number">24</span>);</span><br><span class="line"></span><br><span class="line">std::weak_ptr&lt;<span class="type">int</span>&gt; weakPtr1 = sharedPtr1;</span><br><span class="line">std::weak_ptr&lt;<span class="type">int</span>&gt; weakPtr2 = sharedPtr2;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (weakPtr1.<span class="built_in">owner_before</span>(weakPtr2))</span><br><span class="line">&#123;</span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;weakPtr1&#x27;s object is owned before weakPtr2&#x27;s object&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">&#125; </span><br><span class="line"><span class="keyword">else</span> </span><br><span class="line">&#123;</span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;weakPtr2&#x27;s object is owned before weakPtr1&#x27;s object&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>
</li>
<li><p>**<code>swap()</code>**：交换两个<code>weak_ptr</code>对象的内容。</p>
<p>示例代码：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">std::shared_ptr&lt;<span class="type">int</span>&gt; sharedPtr1 = std::<span class="built_in">make_shared</span>&lt;<span class="type">int</span>&gt;(<span class="number">42</span>);</span><br><span class="line">std::shared_ptr&lt;<span class="type">int</span>&gt; sharedPtr2 = std::<span class="built_in">make_shared</span>&lt;<span class="type">int</span>&gt;(<span class="number">24</span>);</span><br><span class="line"></span><br><span class="line">std::weak_ptr&lt;<span class="type">int</span>&gt; weakPtr1 = sharedPtr1;</span><br><span class="line">std::weak_ptr&lt;<span class="type">int</span>&gt; weakPtr2 = sharedPtr2;</span><br><span class="line"></span><br><span class="line">std::cout &lt;&lt; <span class="string">&quot;Before swap:&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">std::cout &lt;&lt; <span class="string">&quot;weakPtr1 expired? &quot;</span> &lt;&lt; weakPtr1.<span class="built_in">expired</span>() &lt;&lt; std::endl;</span><br><span class="line">std::cout &lt;&lt; <span class="string">&quot;weakPtr2 expired? &quot;</span> &lt;&lt; weakPtr2.<span class="built_in">expired</span>() &lt;&lt; std::endl;</span><br><span class="line"></span><br><span class="line">weakPtr1.<span class="built_in">swap</span>(weakPtr2);</span><br><span class="line"></span><br><span class="line">std::cout &lt;&lt; <span class="string">&quot;After swap:&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">std::cout &lt;&lt; <span class="string">&quot;weakPtr1 expired? &quot;</span> &lt;&lt; weakPtr1.<span class="built_in">expired</span>() &lt;&lt; std::endl;</span><br><span class="line">std::cout &lt;&lt; <span class="string">&quot;weakPtr2 expired? &quot;</span> &lt;&lt; weakPtr2.<span class="built_in">expired</span>() &lt;&lt; std::endl;</span><br></pre></td></tr></table></figure></div>
</li>
<li><p>**<code>operator=</code>**：允许将一个<code>std::weak_ptr</code>对象赋值给另一个<code>std::weak_ptr</code>对象。</p>
<p>赋值操作符执行的是浅拷贝，将右侧的<code>std::weak_ptr</code>对象的状态复制到左侧的对象。</p>
<p>示例代码：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;memory&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    std::shared_ptr&lt;<span class="type">int</span>&gt; sharedPtr1 = std::<span class="built_in">make_shared</span>&lt;<span class="type">int</span>&gt;(<span class="number">42</span>);</span><br><span class="line">    std::shared_ptr&lt;<span class="type">int</span>&gt; sharedPtr2 = std::<span class="built_in">make_shared</span>&lt;<span class="type">int</span>&gt;(<span class="number">24</span>);</span><br><span class="line"></span><br><span class="line">    std::weak_ptr&lt;<span class="type">int</span>&gt; weakPtr1 = sharedPtr1;</span><br><span class="line">    std::weak_ptr&lt;<span class="type">int</span>&gt; weakPtr2 = sharedPtr2;</span><br><span class="line"></span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;weakPtr1 expired? &quot;</span> &lt;&lt; weakPtr1.<span class="built_in">expired</span>() &lt;&lt; std::endl;</span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;weakPtr2 expired? &quot;</span> &lt;&lt; weakPtr2.<span class="built_in">expired</span>() &lt;&lt; std::endl;</span><br><span class="line"></span><br><span class="line">    weakPtr1 = weakPtr2;</span><br><span class="line"></span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;After assignment:&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;weakPtr1 expired? &quot;</span> &lt;&lt; weakPtr1.<span class="built_in">expired</span>() &lt;&lt; std::endl;</span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;weakPtr2 expired? &quot;</span> &lt;&lt; weakPtr2.<span class="built_in">expired</span>() &lt;&lt; std::endl;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>赋值操作符执行的是浅拷贝，只复制了 <code>std::weak_ptr</code> 对象的内部状态，而没有增加引用计数或改变底层的引用关系。</p>
<p>在示例代码的输出中，<code>weakPtr1</code> 的失效状态（即 <code>expired()</code> 返回的值）与 <code>weakPtr2</code> 相同，因为它们指向相同的对象。</p>
<p>使用<code>operator=</code>将一个 <code>std::weak_ptr</code> 对象赋值给另一个，它们将共享相同的状态信息。</p>
</li>
</ul>
<h2 id="相关类和全局函数"><a href="#相关类和全局函数" class="headerlink" title="相关类和全局函数"></a>相关类和全局函数</h2><hr>
<ul>
<li><p>**<code>operator==</code> 和 <code>operator!=</code>**：用于比较两个<code>unique_ptr</code>或<code>shared_ptr</code>对象是否相等或不相等。</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::unique_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr1</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>(<span class="number">1</span>))</span></span>;</span><br><span class="line"><span class="function">std::unique_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr2</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>(<span class="number">2</span>))</span></span>;</span><br><span class="line"><span class="keyword">if</span> (ptr1 == ptr2) </span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">// ptr1和ptr2指向相同的对象</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::shared_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr1</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>(<span class="number">1</span>))</span></span>;</span><br><span class="line"><span class="function">std::shared_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr2</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>(<span class="number">2</span>))</span></span>;</span><br><span class="line"><span class="keyword">if</span> (ptr1 == ptr2) </span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">// ptr1和ptr2指向相同的对象</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>


</li>
<li><p>**<code>operator&lt;</code>, <code>operator&lt;=</code>, <code>operator&gt;</code>, <code>operator&gt;=</code>**：用于比较两个<code>unique_ptr</code>或<code>shared_ptr</code>对象的大小关系（按照指针地址比较）。</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::unique_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr1</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>(<span class="number">1</span>))</span></span>;</span><br><span class="line"><span class="function">std::unique_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr2</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>(<span class="number">2</span>))</span></span>;</span><br><span class="line"><span class="keyword">if</span> (ptr1 &lt; ptr2) </span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">// ptr1的指针地址小于ptr2的指针地址</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">  <span class="function">std::shared_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr1</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>(<span class="number">1</span>))</span></span>;</span><br><span class="line">  <span class="function">std::shared_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr2</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>(<span class="number">2</span>))</span></span>;</span><br><span class="line">  <span class="keyword">if</span> (ptr1 &lt; ptr2)</span><br><span class="line">  &#123;</span><br><span class="line">     <span class="comment">// ptr1的指针地址小于ptr2的指针地址</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">- **`std::hash`**：计算`shared_ptr`对象的哈希值，用于在哈希容器（如`unordered_map`、`unordered_set`）中使用。</span><br><span class="line"></span><br><span class="line">  ```<span class="function">cpp</span></span><br><span class="line"><span class="function">  std::shared_ptr&lt;<span class="type">int</span>&gt; <span class="title">ptr</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>)</span></span>;</span><br><span class="line">  std::hash&lt;std::shared_ptr&lt;<span class="type">int</span>&gt;&gt; hasher;</span><br><span class="line">  std::<span class="type">size_t</span> hashValue = <span class="built_in">hasher</span>(ptr); <span class="comment">// 计算shared_ptr的哈希值</span></span><br></pre></td></tr></table></figure></div>
</li>
<li><p>**<code>std::swap</code>**：用于交换两个智能指针的内容。可以在需要重新分配资源所有权的情况下，高效地交换两个智能指针。</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">cppCopy codestd::shared_ptr&lt;<span class="type">int</span>&gt; ptr1 = std::<span class="built_in">make_shared</span>&lt;<span class="type">int</span>&gt;(<span class="number">42</span>);</span><br><span class="line">std::shared_ptr&lt;<span class="type">int</span>&gt; ptr2 = std::<span class="built_in">make_shared</span>&lt;<span class="type">int</span>&gt;(<span class="number">24</span>);</span><br><span class="line"></span><br><span class="line">std::<span class="built_in">swap</span>(ptr1, ptr2);</span><br></pre></td></tr></table></figure></div>
</li>
<li><p>**<code>std::get_deleter</code>**：用于获取智能指针中的删除器（deleter）的函数模板。可用于访问存储在特定类型智能指针对象中的删除器。</p>
<p>删除器是一种用于在智能指针释放资源时执行自定义清理操作的函数对象即仿函数。</p>
<p><code>std::get_deleter</code>函数接受一个<code>shared_ptr</code>指针对象作为参数，并返回对应的删除器的引用。</p>
<p>它只适用于<code>std::shared_ptr</code>共享指针。对于<code>unique_ptr</code>作为其成员函数。</p>
<p>下面是一个示例，演示如何使用<code>std::get_deleter</code>函数获取智能指针的删除器：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;memory&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">Deleter</span> </span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">operator</span><span class="params">()</span><span class="params">(<span class="type">int</span>* ptr)</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;Deleting resource: &quot;</span> &lt;&lt; *ptr &lt;&lt; std::endl;</span><br><span class="line">        <span class="keyword">delete</span> ptr;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="function">std::shared_ptr&lt;<span class="type">int</span>&gt; <span class="title">sharedPtr</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>(<span class="number">42</span>), Deleter())</span></span>;</span><br><span class="line"></span><br><span class="line">    Deleter* deleter = std::<span class="built_in">get_deleter</span>&lt;Deleter, <span class="type">int</span>&gt;(sharedPtr);</span><br><span class="line">    <span class="comment">// 或者可以使用自动类型推断</span></span><br><span class="line">    <span class="keyword">auto</span> deleter = std::<span class="built_in">get_deleter</span>&lt;Deleter, <span class="type">int</span>&gt;(sharedPtr);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>在这个示例中，首先定义了一个自定义的删除器<code>Deleter</code>，它打印要删除的资源的值，并调用<code>delete</code>来释放内存。</p>
<p>然后，创建了一个<code>std::shared_ptr</code>，并将自定义删除器传递给它们。</p>
<p>接下来，使用<code>std::get_deleter</code>来获取智能指针中的删除器。</p>
<p>最后，可以使用获取到的删除器进行其他操作，例如在需要时手动释放资源。</p>
<p>注意，<code>std::get_deleter</code>的模板参数必须要显式指定删除器类型，智能指针维护的类型可以不显式指定。</p>
<p>示例（这样的代码也是可以的）：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;memory&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">Deleter</span> </span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">operator</span><span class="params">()</span><span class="params">(<span class="type">int</span>* ptr)</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;Deleting resource: &quot;</span> &lt;&lt; *ptr &lt;&lt; std::endl;</span><br><span class="line">        <span class="keyword">delete</span> ptr;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="function">std::shared_ptr&lt;<span class="type">int</span>&gt; <span class="title">sharedPtr</span><span class="params">(<span class="keyword">new</span> <span class="type">int</span>(<span class="number">42</span>), Deleter())</span></span>;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">auto</span> deleter = std::<span class="built_in">get_deleter</span>&lt;Deleter&gt;(sharedPtr);<span class="comment">//不指定智能指针维护的类型</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div></li>
</ul>
<p>更多内容请查阅手册或参考这篇文章：<a class="link"   target="_blank" rel="noopener" href="https://blog.csdn.net/CHYabc123456hh/article/details/109350925" > c++ memory 头文件详细介绍 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p>
<h1 id="final关键字"><a href="#final关键字" class="headerlink" title="final关键字"></a><code>final</code>关键字</h1><p><code>final</code>是C++11中引入的一个新关键字，<code>final</code>关键字用于指示一个类、函数或虚函数不能被继承、重写或覆盖。</p>
<p>它可以被应用于类的声明、虚函数的声明和函数的声明。</p>
<ul>
<li><p>防止类被继承</p>
<p>使用 <code>final</code> 关键字修饰的类不能被继承。这意味着其他类无法派生自该类。</p>
<p>示例：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Base</span> <span class="keyword">final</span> </span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Derived</span> : <span class="keyword">public</span> Base <span class="comment">// 错误，无法从 final 类继承</span></span><br><span class="line">&#123; </span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></div>
</li>
<li><p>防止虚函数被重写</p>
<p>使用 <code>final</code> 关键字修饰的虚函数不能在派生类中被重写或覆盖。</p>
<p>这在继承体系中可以用于禁止派生类修改某个特定的虚函数。</p>
<p>示例：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Base</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">foo</span><span class="params">()</span> <span class="keyword">final</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="comment">// ...</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Derived</span> : <span class="keyword">public</span> Base </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">foo</span><span class="params">()</span> <span class="keyword">override</span>  <span class="comment">// 错误，无法重写 final 虚函数</span></span></span><br><span class="line"><span class="function">    </span>&#123; </span><br><span class="line">        <span class="comment">// ...</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></div>
</li>
<li><p>防止普通函数被重写</p>
<p>使用 <code>final</code> 关键字修饰的普通函数（非虚函数）不能在派生类中被重写。它的作用与 <code>final</code> 虚函数类似，但它适用于非虚函数。</p>
<p>示例：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Base</span> </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">foo</span><span class="params">()</span> <span class="keyword">final</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="comment">// ...</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Derived</span> : <span class="keyword">public</span> Base </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">foo</span><span class="params">()</span> <span class="comment">// 错误，无法重写 final 函数</span></span></span><br><span class="line"><span class="function">    </span>&#123;  </span><br><span class="line">        <span class="comment">// ...</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></div></li>
</ul>
<p>使用<code>final</code>关键字可以在C++中提供额外的控制权，以防止特定类、函数或虚函数被继承、重写或覆盖。</p>
<p>这可以在某些情况下提高代码的安全性和稳定性，以及确保特定实现不会被修改。</p>
<h1 id="override关键字"><a href="#override关键字" class="headerlink" title="override关键字"></a><code>override</code>关键字</h1><p><code>override</code>是C++11中引入的一个新关键字，用于显式地指定某个成员函数为虚函数的重写版本。</p>
<p>当你在派生类中重写基类的虚函数时，可以在该函数的声明后面加上<code>override</code>关键字，表示该函数是重写基类的虚函数。</p>
<p>使用<code>override</code>关键字有两个好处：</p>
<ul>
<li><p>它能够帮助你避免一些常见的错误。</p>
<p>例如：如果你在派生类中重写基类的虚函数时，将函数名或参数列表写错了或者是函数名写错了等。</p>
</li>
<li><p>它能够提高代码的可读性。当其他人阅读你的代码时，看到<code>override</code>关键字，就能够立即知道这是一个重写基类虚函数的函数。</p>
</li>
</ul>
<p>下面是一个简单的例子，演示如何使用<code>override</code>关键字：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Base</span> </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">foo</span><span class="params">()</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;Base::foo()&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Derived</span> : <span class="keyword">public</span> Base </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">foo</span><span class="params">()</span> <span class="keyword">override</span> <span class="comment">//表示这是函数时重写父类虚函数的</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;Derived::foo()&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Base* b = <span class="keyword">new</span> <span class="built_in">Derived</span>();</span><br><span class="line">    b-&gt;<span class="built_in">foo</span>(); <span class="comment">// 输出 &quot;Derived::foo()&quot;</span></span><br><span class="line">    <span class="keyword">delete</span> b;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>在上面的例子中，我们在派生类<code>Derived</code>中重写了基类<code>Base</code>的虚函数<code>foo()</code>。在重写该函数时，我们在函数声明后面加上了<code>override</code>关键字，表示这是一个重写基类虚函数的函数。</p>
<h1 id="inline关键字（内联函数）"><a href="#inline关键字（内联函数）" class="headerlink" title="inline关键字（内联函数）"></a><code>inline</code>关键字（内联函数）</h1><p>内联函数避免了宏函数的一些问题。</p>
<p>内联函数是 C++ 中用来提高函数执行效率的一种方法。它通过在编译时将函数的代码副本放置在每个调用该函数的地方来实现这一目的。</p>
<p>C++ 内联函数是通常与类一起使用。如果一个函数是内联的，那么在编译时，编译器会把该函数的代码副本放置在每个调用该函数的地方。</p>
<p>对内联函数进行任何修改，都需要重新编译函数的所有客户端，因为编译器需要重新更换一次所有的代码，否则将会继续使用旧的函数。</p>
<p>如果想把一个函数定义为内联函数，则需要在函数名前面放置关键字<code>inline</code>，在调用函数之前需要对函数进行定义。</p>
<p>&#x3D;&#x3D;编译器会自动根据函数的开销来选择是否忽略 <code>inline</code>限定符。&#x3D;&#x3D;</p>
<p>&#x3D;&#x3D;在类定义中的定义的函数都是内联函数，即使没有使用<code>inline</code>说明符。&#x3D;&#x3D;</p>
<p>&#x3D;&#x3D;内联仅仅只是给编译器一个建议，编译器不一定会接受这种建议&#x3D;&#x3D;，如果你没有将函数声明为内联函数，那么编译器也可能将此函数做内联编译。</p>
<p>一个好的编译器将会内联小的、简单的函数。</p>
<p>内联函数最适用于小函数，例如访问私有数据成员的函数。这些一行或两行代码的“访问器”函数的主要用途是返回有关对象的状态信息。</p>
<p>内联能提高函数的执行效率，那么为什么不把所有的函数都定义成内联函数呢？<br>内联以代码膨胀（拷贝）为代价，仅仅省区了函数调用的开销，从而提高程序的执行效率。（开销指的是参数的压栈、跳转、退栈和返回操作）。</p>
<p>一方面，如果执行函数体内代码的时间比函数调用的开销大得多，那么<code>inline</code>效率收益会很小。<br>另一方面，每一处内联函数的调用都要拷贝代码，使程序的总代码量增大，消耗更多的内存空间。<br>以下情况不宜使用内联：</p>
<ul>
<li>如果函数体内代码比较长，使用内联将导致可执行代码膨胀过大。</li>
<li>如果函数体内出现循环或者其他复杂的控制结构，那么执行函数体内代码的时间将比函数调用的开销大得多。</li>
</ul>
<p>因此，是否设置为内联需要权衡：</p>
<ul>
<li>如果调用开销大于执行开销，则设为内联函数；</li>
<li>否则不设为内联函数。</li>
</ul>
<p>下面是一个简单的内联函数示例，用来返回两个数中的最大值：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">Max</span><span class="params">(<span class="type">int</span> x, <span class="type">int</span> y)</span> <span class="comment">//一个简单的小函数</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> (x &gt; y)? x : y;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;Max (20,10): &quot;</span> &lt;&lt; <span class="built_in">Max</span>(<span class="number">20</span>,<span class="number">10</span>) &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;Max (0,200): &quot;</span> &lt;&lt; <span class="built_in">Max</span>(<span class="number">0</span>,<span class="number">200</span>) &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;Max (100,1010): &quot;</span> &lt;&lt; <span class="built_in">Max</span>(<span class="number">100</span>,<span class="number">1010</span>) &lt;&lt; endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>当上面的代码被编译和执行时，它会产生下列结果：</p>
<div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Max (20,10): 20</span><br><span class="line">Max (0,200): 200</span><br><span class="line">Max (100,1010): 1010</span><br></pre></td></tr></table></figure></div>

<p><a class="link"   target="_blank" rel="noopener" href="https://learn.microsoft.com/zh-cn/cpp/cpp/inline-functions-cpp?view=msvc-170" >内联函数 (C++) | Microsoft Learn <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a><br> <a class="link"   target="_blank" rel="noopener" href="https://bing.com/search?q=C+++%E5%86%85%E8%81%94%E5%87%BD%E6%95%B0" >c++ 内联函数 （讲解的TM真好） - CSDN博客 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a><br><a class="link"   target="_blank" rel="noopener" href="https://www.runoob.com/cplusplus/cpp-inline-functions.html" >C++ 内联函数 | 菜鸟教程 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a><br><a class="link"   target="_blank" rel="noopener" href="https://blog.csdn.net/u011327981/article/details/50601800" >c++ 内联函数 （讲解的TM真好） - CSDN博客 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a><br><a class="link"   target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/37436574" >C++内联函数能否是虚函数？ - 知乎 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a><br><a class="link"   target="_blank" rel="noopener" href="https://www.cnblogs.com/2018shawn/p/10851779.html" > C++内联函数的使用 - 余生以学 - 博客园 <i class="fa-regular fa-arrow-up-right-from-square fa-sm"></i></a></p>
<p>对于适合成为内联函数的函数，&#x3D;&#x3D;编译器会自动添加<code>inline</code>关键字使之成为内联函数，大部分场景程序员无需手动添加&#x3D;&#x3D;，因此内联函数不作重点，基本了解即可，这里不再做过多讲述，详细见上述的图文、视频讲解链接。</p>
<h1 id="noexcept关键字"><a href="#noexcept关键字" class="headerlink" title="noexcept关键字"></a><code>noexcept</code>关键字</h1><p><code>noexcept</code>用于指定函数是不会抛出异常的。这个关键字对于异常处理和代码优化非常有用。</p>
<p>异常接口声明的特性在C++11被移除，在未被移除之前，声明一个不会抛出异常的函数是这样的：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">func</span><span class="params">()</span> <span class="title">throw</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>该语法在C++11被移除，C++11后声明一个不会抛出异常的函数就要使用<code>noexcept</code>关键字</p>
<p>示例：</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 声明一个会抛出异常的函数</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">mightThrow</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">throw</span> <span class="string">&quot;This function might throw an exception.&quot;</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 声明一个不会引发异常的函数</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">noThrow</span><span class="params">()</span> <span class="keyword">noexcept</span> <span class="comment">//noexcept表示函数不会抛出异常</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;This function will not throw any exception.&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>如果，在有<code>noexcept</code>修饰的函数中抛出了异常，并且在调用时接收了异常，程序则会出现报错或崩溃。</p>
<h1 id="default关键字"><a href="#default关键字" class="headerlink" title="default关键字"></a><code>default</code>关键字</h1><p>在C++中，<code>default</code>关键字用于类中声明默认函数。</p>
<p>类中的默认函数有以下几种：</p>
<ol>
<li>默认构造函数</li>
<li>默认拷贝构造函数</li>
<li>默认拷贝赋值运算符（重载<code>=</code>运算符，参数是左值引用）</li>
<li>默认移动构造函数</li>
<li>默认移动赋值运算符（重载<code>=</code>运算符，参数是右值引用）</li>
<li>默认析构函数</li>
</ol>
<p>默认函数是编译器自动生成的特殊成员函数，用于执行默认的行为。</p>
<p><code>default</code>关键字可以用于以下几个地方：</p>
<ul>
<li><p>声明默认构造函数</p>
<p>如果在类中没有显式定义构造函数，或已经手动定义了有参构造函数，那么编译器就不会自动生成一个默认构造函数。</p>
<p>这时候在创建一个类对象时如果不想立即初始化，就会无法调用默认构造函数，导致编译报错。</p>
<p>示例：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">MyClass</span> </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">MyClass</span>(<span class="type">int</span> x) </span><br><span class="line">    &#123;</span><br><span class="line">    	a = x;    </span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="type">int</span> a;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Myclass A;<span class="comment">//编译报错，没有默认构造。因为手动定义了有参构造，编译器不再提供默认构造</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>可以使用<code>default</code>关键字来显式声明默认构造函数</p>
<p>示例：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">MyClass</span> </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">MyClass</span>() = <span class="keyword">default</span>; <span class="comment">// 声明默认构造函数</span></span><br><span class="line">    </span><br><span class="line">    <span class="built_in">MyClass</span>(<span class="type">int</span> x) </span><br><span class="line">    &#123;</span><br><span class="line">    	a = x;    </span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="type">int</span> a;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Myclass A;<span class="comment">//编译通过</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>
</li>
<li><p>声明默认拷贝构造函数</p>
<p>如果在类中没有显式定义拷贝构造函数，编译器会自动生成一个默认拷贝构造函数。</p>
<p>可以使用<code>default</code>关键字来显式声明默认拷贝构造函数</p>
<p>例如：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">MyClass</span> </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">MyClass</span>(<span class="type">const</span> MyClass&amp; other) = <span class="keyword">default</span>; <span class="comment">// 声明默认拷贝构造函数</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></div>
</li>
<li><p>声明默认拷贝赋值运算符</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">MyClass</span> </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    MyClass&amp; <span class="keyword">operator</span>=(<span class="type">const</span> MyClass&amp; other) = <span class="keyword">default</span>; <span class="comment">// 声明默认拷贝赋值运算符</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></div>
</li>
<li><p>声明默认移动构造函数</p>
<p>C++11引入了移动语义，可以通过移动构造函数和移动赋值运算符实现高效的资源管理。</p>
<p>如果在类中没有显式定义移动构造函数和移动赋值运算符，编译器会自动生成默认的移动构造函数和移动赋值运算符。</p>
<p>可以使用<code>default</code>关键字来显式声明默认移动构造函数和移动赋值运算符，</p>
<p>例如：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">MyClass</span> </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">MyClass</span>(MyClass&amp;&amp; other) = <span class="keyword">default</span>; <span class="comment">// 声明默认移动构造函数</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></div>
</li>
<li><p>声明默认移动赋值运算符</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">MyClass</span> </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    MyClass&amp; <span class="keyword">operator</span>=(MyClass&amp;&amp; other) = <span class="keyword">default</span>; <span class="comment">// 声明默认移动赋值运算符</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></div>
</li>
<li><p>声明默认析构函数</p>
<p>如果在类中没有显式定义析构函数，编译器会自动生成一个默认析构函数。</p>
<p>可以使用<code>default</code>关键字来显式声明默认析构函数。</p>
<p>例如：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">MyClass</span> </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    ~<span class="built_in">MyClass</span>() = <span class="keyword">default</span>; <span class="comment">// 声明默认析构函数</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></div></li>
</ul>
<p><code>default</code>也可以在类外使用。</p>
<p>示例：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">MyClass</span> </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">MyClass</span>();</span><br><span class="line">&#125;;</span><br><span class="line">MyClass::<span class="built_in">MyClass</span>() = <span class="keyword">default</span>;</span><br></pre></td></tr></table></figure></div>

<p>通过使用<code>default</code>关键字，可以显式声明使用编译器生成的默认函数，这对于需要手动定义其他函数而又需要默认函数的情况非常有用。</p>
<h1 id="delete禁用函数"><a href="#delete禁用函数" class="headerlink" title="=delete禁用函数"></a><code>=delete</code>禁用函数</h1><p>为了能够让程序员显式的禁用某个函数，C++11标准引入了一个新特性：使用<code>=delete</code>修饰函数。</p>
<p>只需在函数声明后上<code>=delete</code>，就可将该函数禁用。</p>
<p>示例：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">MyClass</span> </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="comment">// 禁用默认构造函数</span></span><br><span class="line">    <span class="built_in">MyClass</span>() = <span class="keyword">delete</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 禁用拷贝构造函数</span></span><br><span class="line">    <span class="built_in">MyClass</span>(<span class="type">const</span> MyClass&amp;) = <span class="keyword">delete</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 禁用拷贝赋值运算符</span></span><br><span class="line">    MyClass&amp; <span class="keyword">operator</span>=(<span class="type">const</span> MyClass&amp;) = <span class="keyword">delete</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 禁用析构函数</span></span><br><span class="line">    ~<span class="built_in">MyClass</span>() = <span class="keyword">delete</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 禁用特定的成员函数</span></span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">doSomething</span><span class="params">()</span> </span>= <span class="keyword">delete</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    MyClass obj; <span class="comment">// 编译错误，禁用了默认构造函数</span></span><br><span class="line"></span><br><span class="line">    MyClass obj1;</span><br><span class="line">    MyClass obj2 = obj1; <span class="comment">// 编译错误，禁用了拷贝构造函数</span></span><br><span class="line"></span><br><span class="line">    obj1 = obj2; <span class="comment">// 编译错误，禁用了拷贝赋值运算符</span></span><br><span class="line"></span><br><span class="line">    obj1.<span class="built_in">doSomething</span>(); <span class="comment">// 编译错误，禁用了特定的成员函数</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure></div>

<h1 id="使用using取别名"><a href="#使用using取别名" class="headerlink" title="使用using取别名"></a>使用<code>using</code>取别名</h1><p>在C++11中，使用<code>using</code>关键字可以用来为类型创建别名。</p>
<p>它与<code>typedef</code>有一些区别，下面是它们之间的主要区别：</p>
<ul>
<li><p>语法：</p>
<p><code>using</code>语法相对更加直观和一致。</p>
<p>它使用类似于变量赋值的语法，如<code>using NewName = OldType;</code></p>
<p>而<code>typedef</code>则使用一个稍微有些独特的语法，如<code>typedef OldType NewName;</code></p>
</li>
<li><p>支持模板别名：</p>
<p><code>using</code>关键字支持为模板类型创建别名，</p>
<p>例如：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">typename</span> T&gt;</span><br><span class="line"><span class="keyword">using</span> Vector = std::vector&lt;T&gt;;</span><br></pre></td></tr></table></figure></div>

<p>这里<code>Vector</code>是<code>std::vector</code>的别名，它可以用来创建具有相同类型元素的向量。</p>
</li>
<li><p>嵌套类型别名：<code>using</code>关键字可以在类内部为嵌套类型创建别名，而<code>typedef</code>不能直接在类内部使用，需要借助<code>typedef</code>在类外部进行定义。</p>
</li>
<li><p>模板参数位置：在模板定义时，<code>using</code>关键字可以在任意位置指定模板参数，而<code>typedef</code>只能在定义之前指定模板参数。</p>
</li>
<li><p>右结合性：<code>using</code>关键字的右结合性使得它更容易使用模板元编程和模板别名的复杂技术。</p>
</li>
</ul>
<p><code>using</code>关键字在C++11中提供了更加灵活和直观的方式来创建类型别名，并且它还支持模板别名和嵌套类型别名，这些是<code>typedef</code>所没有的特性。</p>
<p>因此，推荐使用<code>using</code>关键字来创建类型别名。但为了保持与旧代码的兼容性，<code>typedef</code>仍然被广泛使用。</p>
<h1 id="函数模板的默认模板参数"><a href="#函数模板的默认模板参数" class="headerlink" title="函数模板的默认模板参数"></a>函数模板的默认模板参数</h1><p>C++11前类模板是支持默认的模板参数的，却不支持函数模板的默认模板参数。</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//1、普通函数带默认参数，c++98编译通过，c++11编译通过</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">DefParm</span><span class="params">(<span class="type">int</span> m=<span class="number">3</span>)</span></span>&#123;&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//2、类模板是支持默认的模板参数，c++98编译通过，c++11编译通过</span></span><br><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">typename</span> T = <span class="type">int</span>&gt;<span class="keyword">class</span> DefClass;</span><br><span class="line"></span><br><span class="line"><span class="comment">//3、函数模板的默认模板参数，c++98-编译失败，c++11-编译通过</span></span><br><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">typename</span> T= <span class="type">int</span>&gt; <span class="type">void</span> <span class="built_in">DefTempParm</span>()&#123;&#125;</span><br></pre></td></tr></table></figure></div>

<p>  类模板的默认模板参数必须从右往左定义，数模板的默认模板参数则没这个限定：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">typename</span> T ,<span class="keyword">class</span> <span class="title class_">T2</span>= <span class="type">int</span>&gt;<span class="keyword">class</span> DefClass&#123;&#125;;<span class="comment">//编译正确</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">typename</span> T= <span class="type">int</span> ,<span class="keyword">class</span> T2&gt;<span class="keyword">class</span> DefClass&#123;&#125;;<span class="comment">//编译错误</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">template</span>&lt;<span class="keyword">class</span> T1 </span>= <span class="type">int</span>, <span class="keyword">class</span> <span class="title class_">T2</span>&gt; <span class="function"><span class="type">void</span> <span class="title">DefFunc1</span><span class="params">(T1 a,T2 b)</span></span>&#123;&#125;;<span class="comment">//函数模板无限制，编译通过</span></span><br></pre></td></tr></table></figure></div>



<h1 id="可变参数模板"><a href="#可变参数模板" class="headerlink" title="可变参数模板"></a>可变参数模板</h1><h2 id="可变参数函数模板"><a href="#可变参数函数模板" class="headerlink" title="可变参数函数模板"></a>可变参数函数模板</h2><p>C++11引入了可变参数模板（Variadic Templates）的特性，它允许在模板中接受任意数量的参数。</p>
<p>这个特性非常有用，因为它可以用于编写更加通用和灵活的代码。</p>
<p>变参数模板使用<code>...</code>语法来表示：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span>&lt;<span class="keyword">class</span> ...T&gt;<span class="comment">//T叫模板参数包</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">func</span> <span class="params">(T... args)</span> <span class="comment">// args叫函数参数包</span></span></span><br></pre></td></tr></table></figure></div>

<p>示例：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="comment">//可变参数的模板函数</span></span><br><span class="line"><span class="keyword">template</span>&lt;<span class="keyword">class</span> ... T&gt;<span class="comment">//T叫模板参数包</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">func</span> <span class="params">(T... args)</span> <span class="comment">//args叫函数参数包</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span> <span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="built_in">func</span>&lt;<span class="type">int</span>&gt; (<span class="number">10</span>);</span><br><span class="line">	<span class="built_in">func</span>&lt;<span class="type">int</span>, <span class="type">int</span>&gt; (<span class="number">10</span>,<span class="number">20</span>);</span><br><span class="line">    <span class="built_in">func</span>&lt;<span class="type">char</span>, <span class="type">int</span>&gt; (<span class="number">10</span>, <span class="string">&#x27;a&#x27;</span> );</span><br><span class="line">	<span class="built_in">func</span>&lt;<span class="type">char</span>,<span class="type">char</span> *, <span class="type">int</span>&gt; (<span class="string">&#x27;a&#x27;</span>, <span class="string">&quot;abc&quot;</span>,<span class="number">250</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>上面的代码编译是可以通过的。</p>
<p>一个使用可变参数模板的函数模板的例子：</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 基本情况：当没有参数时，递归终止</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">print</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    std::cout &lt;&lt; std::endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 递归调用：打印第一个参数，然后调用自身打印剩余参数</span></span><br><span class="line"><span class="function"><span class="keyword">template</span>&lt;<span class="keyword">typename</span> T, <span class="keyword">typename</span>... Args&gt;</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">print</span><span class="params">(<span class="type">const</span> T&amp; first, <span class="type">const</span> Args&amp;... args)</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    std::cout &lt;&lt; first &lt;&lt; <span class="string">&quot; &quot;</span>;</span><br><span class="line">    <span class="built_in">print</span>(args...);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="built_in">print</span>(<span class="number">1</span>, <span class="string">&quot;Hello&quot;</span>, <span class="number">3.14</span>, <span class="string">&#x27;A&#x27;</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>输出：</p>
<div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">1 Hello 3.14 A</span><br></pre></td></tr></table></figure></div>

<p>在上面的代码中，我们定义了一个可变参数模板函数<code>print</code>，它可以接受任意数量的参数并将它们打印到标准输出。</p>
<p>在递归调用中，我们首先打印第一个参数<code>first</code>，然后通过<code>args...</code>将剩余的参数传递给自身进行递归调用。</p>
<p>当我们在<code>main</code>函数中调用<code>print</code>函数时，我们传递了四个参数：</p>
<p>整数1，字符串”Hello”，浮点数3.14和字符’A’。</p>
<p>由于<code>print</code>函数是可变参数模板，它能够接受这四个参数并将它们全部打印出来。</p>
<h2 id="可变参数类模板"><a href="#可变参数类模板" class="headerlink" title="可变参数类模板"></a>可变参数类模板</h2><p>除了函数模板，我们还可以使用可变参数模板来定义类模板。</p>
<p>以下是一个简单的示例：</p>
<div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span>&lt;<span class="keyword">typename</span>... Args&gt;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Tuple</span> </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Tuple</span>(<span class="type">const</span> Args&amp;... args) : values&#123;args...&#125; &#123;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">print</span><span class="params">()</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="built_in">printHelper</span>(values);</span><br><span class="line">        std::cout &lt;&lt; std::endl;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="function"><span class="keyword">template</span>&lt;<span class="keyword">typename</span> T&gt;</span></span><br><span class="line"><span class="function">    <span class="type">void</span> <span class="title">printHelper</span><span class="params">(<span class="type">const</span> T&amp; value)</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        std::cout &lt;&lt; value &lt;&lt; <span class="string">&quot; &quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">template</span>&lt;<span class="keyword">typename</span> T, <span class="keyword">typename</span>... Rest&gt;</span></span><br><span class="line"><span class="function">    <span class="type">void</span> <span class="title">printHelper</span><span class="params">(<span class="type">const</span> T&amp; first, <span class="type">const</span> Rest&amp;... rest)</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        std::cout &lt;&lt; first &lt;&lt; <span class="string">&quot; &quot;</span>;</span><br><span class="line">        <span class="built_in">printHelper</span>(rest...);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    std::tuple&lt;Args...&gt; values;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="function">Tuple&lt;<span class="type">int</span>, std::string, <span class="type">double</span>&gt; <span class="title">t</span><span class="params">(<span class="number">42</span>, <span class="string">&quot;Hello&quot;</span>, <span class="number">3.14</span>)</span></span>;</span><br><span class="line">    t.<span class="built_in">print</span>();</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>在上面的代码中，我们定义了一个名为<code>Tuple</code>的类模板，它使用可变参数模板来接受任意数量的类型参数。</p>
<p>在构造函数中，我们将传递的参数打包成一个<code>std::tuple</code>对象来保存。</p>
<p>类模板中的<code>print</code>函数使用递归的方式打印保存的值。</p>
<p>我们使用类内嵌的辅助函数<code>printHelper</code>来实现递归，类似于前面函数模板的例子。</p>
<p>在<code>main</code>函数中，我们创建了一个<code>Tuple</code>对象，类型参数为<code>int</code>，<code>std::string</code>和<code>double</code>，并传递了相应的值。</p>
<p>然后，我们调用<code>print</code>函数来打印这些值。</p>
<p>输出结果将是：<code>42 Hello 3.14</code>。</p>
<h2 id="获取可变参数模板的参数个数"><a href="#获取可变参数模板的参数个数" class="headerlink" title="获取可变参数模板的参数个数"></a>获取可变参数模板的参数个数</h2><p>使用<code>sizeof...(Args)</code>可以获取可变参数模板的参数个数。</p>
<p><code>sizeof...()</code>是一个C++的运算符，用于计算可变参数模板的参数个数。</p>
<p>它返回一个<code>size_t</code>类型的值，表示参数的数量。</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="comment">//可变参数的模板函数</span></span><br><span class="line"><span class="keyword">template</span>&lt;<span class="keyword">class</span> ... T&gt;<span class="comment">//T叫模板参数包</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">func</span> <span class="params">(T... args)</span> <span class="comment">//args叫函数参数包</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="comment">//获取可变参数的个数</span></span><br><span class="line">	cout &lt;&lt;<span class="string">&quot;num = &quot;</span> &lt;&lt;<span class="keyword">sizeof</span>.. . (args) &lt;&lt;endl;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span> <span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="built_in">func</span>&lt;<span class="type">int</span>&gt; (<span class="number">10</span>);</span><br><span class="line">	<span class="built_in">func</span>&lt;<span class="type">int</span>, <span class="type">int</span>&gt; (<span class="number">10</span>,<span class="number">20</span>);</span><br><span class="line">    <span class="built_in">func</span>&lt;<span class="type">char</span>, <span class="type">int</span>&gt; (<span class="number">10</span>, <span class="string">&#x27;a&#x27;</span> );</span><br><span class="line">	<span class="built_in">func</span>&lt;<span class="type">char</span>,<span class="type">char</span> *, <span class="type">int</span>&gt; (<span class="string">&#x27;a&#x27;</span>, <span class="string">&quot;abc&quot;</span>,<span class="number">250</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>输出：</p>
<div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">num = 1</span><br><span class="line">num = 2</span><br><span class="line">num = 2</span><br><span class="line">num = 3</span><br></pre></td></tr></table></figure></div>

<p>需要注意的是，<code>sizeof...(Args)</code>是在编译时计算的，因此它提供了在编译期间获取参数个数的能力。这使得可以在编译时进行相关的优化和决策。</p>
<h2 id="模板特化"><a href="#模板特化" class="headerlink" title="模板特化"></a>模板特化</h2><p>模板特化（Template specialization）是C++中一种用于为特定类型或特定模板参数提供自定义实现的机制。</p>
<p>它允许我们根据特定的类型或参数来定义特定版本的模板函数或模板类，以满足特定的需求或提供特定的行为。</p>
<p>模板特化可以分为两种类型：全特化（Full specialization）和偏特化（Partial specialization）。</p>
<ul>
<li><p>全特化（Full specialization）：全特化是针对特定类型或特定参数的完整定义。在全特化中，我们提供了特定类型或参数的实现，完全替代了原始的模板定义。全特化的语法形式为：</p>
 <div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span>&lt;<span class="keyword">typename</span> T&gt;</span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">MyTemplate</span> &#123;</span><br><span class="line">    <span class="comment">// 通用实现</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span>&lt;&gt;</span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">MyTemplate</span>&lt;<span class="type">int</span>&gt; &#123;</span><br><span class="line">    <span class="comment">// int 类型的特化实现</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></div>

<p> 在上述示例中，我们定义了一个通用的模板类<code>MyTemplate</code>，并通过全特化为<code>int</code>类型提供了一个特殊的实现。</p>
</li>
<li><p>偏特化（Partial specialization）：偏特化是针对模板参数的部分定义。它允许我们根据参数的特定属性或限制来提供不同的实现。偏特化的语法形式为：</p>
 <div class="highlight-container" data-rel="Cpp"><figure class="iseeu highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span>&lt;<span class="keyword">typename</span> T, <span class="keyword">typename</span> U&gt;</span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">MyTemplate</span> &#123;</span><br><span class="line">    <span class="comment">// 通用实现</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span>&lt;<span class="keyword">typename</span> T&gt;</span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">MyTemplate</span>&lt;T, <span class="type">int</span>&gt; &#123;</span><br><span class="line">    <span class="comment">// T 和 int 类型的偏特化实现</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></div>

<p> 在上述示例中，我们定义了一个通用的模板类<code>MyTemplate</code>，并通过偏特化为<code>T</code>和<code>int</code>类型的组合提供了一个特殊的实现。</p>
</li>
</ul>
<p>模板特化使我们能够为特定的类型或参数提供自定义的行为，以满足特殊的需求或提供更精确的实现。</p>
<p>它在泛型编程中起到了非常重要的作用，并且是C++模板系统的强大功能之一。</p>
<h2 id="函数模板参数包的展开"><a href="#函数模板参数包的展开" class="headerlink" title="函数模板参数包的展开"></a>函数模板参数包的展开</h2><h3 id="递归和模板特化展开"><a href="#递归和模板特化展开" class="headerlink" title="递归和模板特化展开"></a>递归和模板特化展开</h3><p>通过递归函数展开参数包，需要提供一个参数包展开的函数和一个递归终止函数。</p>
<p>示例代码：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="comment">//当最后没有参数时调用这个</span></span><br><span class="line"><span class="comment">//递归终止函数1</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">debug</span> <span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	cout &lt;&lt; <span class="string">&quot;empty&quot;</span> &lt;&lt; endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*也可以这样写，当最后只有一个参数时调用这个函数</span></span><br><span class="line"><span class="comment">//递归终止函数2</span></span><br><span class="line"><span class="comment">template&lt;class T&gt;</span></span><br><span class="line"><span class="comment">void debug (T tmp)</span></span><br><span class="line"><span class="comment">&#123;</span></span><br><span class="line"><span class="comment">	cout &lt;&lt;&quot;tmp = &quot; &lt;&lt;tmp &lt;&lt;endl ;</span></span><br><span class="line"><span class="comment">&#125;</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="comment">//以此类推，可以根据需要指定递归终止函数的调用参数</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//可变参数的模板函数</span></span><br><span class="line"><span class="comment">//参数包展开函数</span></span><br><span class="line"><span class="function"><span class="keyword">template</span>&lt;<span class="keyword">class</span> T1,<span class="keyword">class</span> ... T2&gt;</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">debug</span> <span class="params">(T1 first,T2... last)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	cout &lt;&lt; first &lt;&lt; endl;<span class="comment">//递归调用函数本身</span></span><br><span class="line">	<span class="built_in">debug</span> ( last... );</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span> <span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="built_in">debug</span> ( <span class="number">1</span>, <span class="number">2</span>,<span class="number">3</span>, <span class="number">4</span>) ;</span><br><span class="line">	 <span class="comment">/*	函数递归调用过程:</span></span><br><span class="line"><span class="comment">		debug (1，2，3,4);</span></span><br><span class="line"><span class="comment">		debug (2，3,4);</span></span><br><span class="line"><span class="comment">		debug (3,4) ;</span></span><br><span class="line"><span class="comment">		debug (4);</span></span><br><span class="line"><span class="comment">		debug ();	*/</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<h3 id="递归、逗号和初始化列表展开"><a href="#递归、逗号和初始化列表展开" class="headerlink" title="递归、逗号和初始化列表展开"></a>递归、逗号和初始化列表展开</h3><p>使用场景较少，不推荐使用</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">template</span>&lt;<span class="keyword">class</span> T&gt;</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">print</span> <span class="params">(T tmp)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	cout &lt;&lt; tmp &lt;&lt; endl;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//可变参数的模板函数</span></span><br><span class="line"><span class="function"><span class="keyword">template</span>&lt;<span class="keyword">class</span> ...T&gt;</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">expand</span><span class="params">(T ... args)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="comment">//逗号运算符</span></span><br><span class="line">    <span class="comment">//初始化列表</span></span><br><span class="line">	<span class="type">int</span> a[] = &#123; (<span class="built_in">print</span> (args), <span class="number">0</span>) ...&#125;;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span> <span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="built_in">expand</span> (<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>);</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<h3 id="折叠表达式（C-17起）展开"><a href="#折叠表达式（C-17起）展开" class="headerlink" title="折叠表达式（C++17起）展开"></a>折叠表达式（C++17起）展开</h3><div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">template</span>&lt;<span class="keyword">typename</span>... Args&gt;</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">baz</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="comment">// 使用折叠表达式展开参数包</span></span><br><span class="line">	((std::cout &lt;&lt; <span class="built_in">typeid</span>(Args).<span class="built_in">name</span>() &lt;&lt; std::endl), ...);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	baz&lt;<span class="type">int</span>, <span class="type">double</span>, <span class="type">char</span>*, std::vector&lt;std::list&lt;<span class="type">int</span>, std::string&gt;&gt;&gt;();</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>输出（因为屏幕长度显示，最后三行换行了）：</p>
<div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">int</span><br><span class="line">double</span><br><span class="line">char * __ptr64</span><br><span class="line">class std::vector&lt;class std::list&lt;int,class std::basic_string&lt;char,struct std::char_traits&lt;char&gt;,class std::allocator&lt;char&gt; &gt; &gt;,class std::allocator&lt;class std::list&lt;int,class std::basic_string&lt;char,struct std::char_traits&lt;char&gt;,class std::allocator&lt;char&gt; &gt; &gt; &gt; &gt;</span><br></pre></td></tr></table></figure></div>

<h2 id="类模板参数包的展开"><a href="#类模板参数包的展开" class="headerlink" title="类模板参数包的展开"></a>类模板参数包的展开</h2><h3 id="继承方式展开"><a href="#继承方式展开" class="headerlink" title="继承方式展开"></a>继承方式展开</h3><p>继承方式展开可变参数模板类的步骤：</p>
<ul>
<li>可变参数模板声明</li>
<li>递归继承模板类</li>
<li>递归终止条件</li>
</ul>
<p>示例：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//1.可变参数模板声明</span></span><br><span class="line"><span class="keyword">template</span>&lt;<span class="keyword">class</span>...T&gt;<span class="keyword">class</span> <span class="title class_">Car</span> &#123;&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//2.递归继承模板类本身</span></span><br><span class="line"><span class="keyword">template</span>&lt;<span class="keyword">class</span> <span class="title class_">Head</span>, <span class="keyword">class</span> ...Tail&gt;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Car</span>&lt;Head, Tail...&gt; :<span class="keyword">public</span> Car&lt;Tail...&gt;</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">	<span class="built_in">Car</span>()</span><br><span class="line">	&#123;</span><br><span class="line">		std::cout &lt;&lt; <span class="string">&quot;type = &quot;</span> &lt;&lt; <span class="built_in">typeid</span>(Head).<span class="built_in">name</span>() &lt;&lt; std::endl;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//3.递归终止条件</span></span><br><span class="line"><span class="keyword">template</span>&lt;&gt;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Car</span>&lt;&gt; &#123;&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span> <span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;    </span><br><span class="line">	Car&lt;<span class="type">int</span>, std::string, <span class="type">const</span> <span class="type">char</span>*, <span class="type">bool</span>&gt; byd;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>输出：</p>
<div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">type = bool</span><br><span class="line">type = char const * __ptr64</span><br><span class="line">type = class std::basic_string&lt;char,struct std::char_traits&lt;char&gt;,class std::allocator&lt;char&gt; &gt;</span><br><span class="line">type = int</span><br></pre></td></tr></table></figure></div>

<h3 id="递归和特例化展开"><a href="#递归和特例化展开" class="headerlink" title="递归和特例化展开"></a>递归和特例化展开</h3><ul>
<li>变长模板声明</li>
<li>变长模板类定义</li>
<li>递归终止</li>
</ul>
<p>示例：</p>
<div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//1.变长模板声明</span></span><br><span class="line"><span class="keyword">template</span>&lt;<span class="type">int</span> ...last&gt;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Test</span> &#123;&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//2.变长模板类定义</span></span><br><span class="line"><span class="keyword">template</span>&lt;<span class="type">int</span> first, <span class="type">int</span> ...last&gt;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Test</span>&lt;first, last...&gt;</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">	<span class="type">static</span> <span class="type">const</span> <span class="type">int</span> val = first * Test&lt;last...&gt;::val;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//3.递归终止</span></span><br><span class="line"><span class="keyword">template</span>&lt;&gt;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Test</span>&lt;&gt;</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">	<span class="type">static</span> <span class="type">const</span> <span class="type">int</span> val = <span class="number">1</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span> <span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;    </span><br><span class="line">	std::cout &lt;&lt; Test&lt;<span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>&gt;::val &lt;&lt; std::endl;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<h3 id="折叠表达式（C-17起）展开-1"><a href="#折叠表达式（C-17起）展开-1" class="headerlink" title="折叠表达式（C++17起）展开"></a>折叠表达式（C++17起）展开</h3><div class="highlight-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span>&lt;<span class="keyword">typename</span>... Args&gt;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyTemplate</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">	<span class="function"><span class="type">void</span> <span class="title">process</span><span class="params">()</span></span></span><br><span class="line"><span class="function">	</span>&#123;</span><br><span class="line">		<span class="comment">// 使用折叠表达式展开参数包</span></span><br><span class="line">		((std::cout &lt;&lt; <span class="built_in">typeid</span>(Args).<span class="built_in">name</span>() &lt;&lt; std::endl), ...);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line"></span><br><span class="line">	MyTemplate&lt;<span class="type">int</span>, <span class="type">char</span>, std::string, <span class="type">const</span> <span class="type">char</span>*&gt; test;</span><br><span class="line">	test.<span class="built_in">process</span>();</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>输出：</p>
<div class="highlight-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">int</span><br><span class="line">char</span><br><span class="line">class std::basic_string&lt;char,struct std::char_traits&lt;char&gt;,class std::allocator&lt;char&gt; &gt;</span><br><span class="line">char const * __ptr64</span><br></pre></td></tr></table></figure></div>


        </div>

        

        
            <ul class="post-tags-box">
                
                    <li class="tag-item">
                        <a href="/tags/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/">#学习笔记</a>&nbsp;
                    </li>
                
            </ul>
        

        

        
            <div class="article-nav">
                
                    <div class="article-prev">
                        <a class="prev"
                        rel="prev"
                        href="/2023/09/17/%E5%89%8D%E7%AB%AFWeb%E5%BC%80%E5%8F%91-HTML5-CSS-JS%E7%AC%94%E8%AE%B0/"
                        >
                            <span class="left arrow-icon flex justify-center items-center">
                                <i class="fa-solid fa-chevron-left"></i>
                            </span>
                            <span class="title flex justify-center items-center">
                                <span class="post-nav-title-item">前端Web开发(HTML5+CSS+JS笔记)</span>
                                <span class="post-nav-item">上一篇</span>
                            </span>
                        </a>
                    </div>
                
                
                    <div class="article-next">
                        <a class="next"
                        rel="next"
                        href="/2023/09/17/CPP-%E5%9F%BA%E7%A1%80/"
                        >
                            <span class="title flex justify-center items-center">
                                <span class="post-nav-title-item">C++基础</span>
                                <span class="post-nav-item">下一篇</span>
                            </span>
                            <span class="right arrow-icon flex justify-center items-center">
                                <i class="fa-solid fa-chevron-right"></i>
                            </span>
                        </a>
                    </div>
                
            </div>
        


        
    </div>

    
        <div class="toc-content-container">
            <div class="post-toc-wrap">
    <div class="post-toc">
        <div class="toc-title">此页目录</div>
        <div class="page-title">C++11起-新特性</div>
        <ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%88%97%E8%A1%A8%E5%88%9D%E5%A7%8B%E5%8C%96"><span class="nav-text">列表初始化</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%88%9D%E5%A7%8B%E5%8C%96%E8%B5%8B%E5%80%BC"><span class="nav-text">初始化赋值</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%88%97%E8%A1%A8%E5%88%9D%E5%A7%8B%E5%8C%96%E9%98%B2%E6%AD%A2%E7%B1%BB%E5%9E%8B%E6%94%B6%E7%AA%84"><span class="nav-text">列表初始化防止类型收窄</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%8E%9F%E5%A7%8B%E5%AD%97%E9%9D%A2%E9%87%8F"><span class="nav-text">原始字面量</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E8%87%AA%E5%8A%A8%E7%B1%BB%E5%9E%8B%E6%8E%A8%E5%AF%BC"><span class="nav-text">自动类型推导</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#auto%E8%87%AA%E5%8A%A8%E7%B1%BB%E5%9E%8B%E6%8E%A8%E5%AF%BC"><span class="nav-text">auto自动类型推导</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BD%BF%E7%94%A8%E7%A4%BA%E4%BE%8B"><span class="nav-text">使用示例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%8E%A8%E5%AF%BC%E8%A7%84%E5%88%99"><span class="nav-text">推导规则</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9"><span class="nav-text">注意事项</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#decltype%E8%87%AA%E5%8A%A8%E7%B1%BB%E5%9E%8B%E6%8E%A8%E5%AF%BC"><span class="nav-text">decltype自动类型推导</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BD%BF%E7%94%A8%E7%A4%BA%E4%BE%8B-1"><span class="nav-text">使用示例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%8E%A8%E5%AF%BC%E8%A7%84%E5%88%99-1"><span class="nav-text">推导规则</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%BF%BD%E8%B8%AA%E8%BF%94%E5%9B%9E%E7%B1%BB%E5%9E%8B"><span class="nav-text">追踪返回类型</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%99%AE%E9%80%9A%E5%87%BD%E6%95%B0"><span class="nav-text">普通函数</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%A8%A1%E6%9D%BF%E5%87%BD%E6%95%B0"><span class="nav-text">模板函数</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%85%B6%E4%BB%96%E7%A4%BA%E4%BE%8B"><span class="nav-text">其他示例</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E8%8C%83%E5%9B%B4for%E5%BE%AA%E7%8E%AF"><span class="nav-text">范围for循环</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E9%9D%99%E6%80%81%E6%96%AD%E8%A8%80"><span class="nav-text">静态断言</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%BD%BF%E7%94%A8nullptr%E5%8F%96%E4%BB%A3NULL"><span class="nav-text">使用nullptr取代NULL</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%BC%BA%E7%B1%BB%E5%9E%8B%E6%9E%9A%E4%B8%BE"><span class="nav-text">强类型枚举</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%BC%A0%E7%BB%9F%E6%9E%9A%E4%B8%BE%E7%9A%84%E5%B1%80%E9%99%90%E6%80%A7"><span class="nav-text">传统枚举的局限性</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#C-11%E5%BC%BA%E7%B1%BB%E5%9E%8B%E6%9E%9A%E4%B8%BE"><span class="nav-text">C++11强类型枚举</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%89%8D%E7%BD%AE%E5%A3%B0%E6%98%8E%E7%9A%84%E5%86%99%E6%B3%95"><span class="nav-text">前置声明的写法</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8F%82%E8%80%83"><span class="nav-text">参考</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#constexpr%E4%BF%AE%E9%A5%B0%E7%9A%84%E5%8F%98%E9%87%8F%E5%92%8C%E8%A1%A8%E8%BE%BE%E5%BC%8F"><span class="nav-text">constexpr修饰的变量和表达式</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%A6%82%E5%BF%B5%E5%92%8C%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95"><span class="nav-text">概念和使用方法</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#constexpr%E4%BF%AE%E9%A5%B0%E5%87%BD%E6%95%B0%E7%9A%84%E9%99%90%E5%88%B6"><span class="nav-text">constexpr修饰函数的限制</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#constexpr%E4%BF%AE%E9%A5%B0%E7%B1%BB%E7%9A%84%E6%88%90%E5%91%98%E5%87%BD%E6%95%B0"><span class="nav-text">constexpr修饰类的成员函数</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E7%94%A8%E6%88%B7%E8%87%AA%E5%AE%9A%E4%B9%89%E5%AD%97%E9%9D%A2%E9%87%8F"><span class="nav-text">用户自定义字面量</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#C-%E4%B8%AD%E7%9A%84%E5%AD%97%E9%9D%A2%E9%87%8F"><span class="nav-text">C++中的字面量</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%94%A8%E6%88%B7%E8%87%AA%E5%AE%9A%E4%B9%89%E5%AD%97%E9%9D%A2%E9%87%8F%E5%90%8E%E7%BC%80"><span class="nav-text">用户自定义字面量后缀</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%87%AA%E5%AE%9A%E4%B9%89%E5%AD%97%E9%9D%A2%E9%87%8F%E7%9A%84%E9%99%90%E5%88%B6"><span class="nav-text">自定义字面量的限制</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF%E7%A4%BA%E4%BE%8B"><span class="nav-text">使用场景示例</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%8F%B3%E5%80%BC%E5%BC%95%E7%94%A8"><span class="nav-text">右值引用</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%B7%A6%E5%80%BC%E5%92%8C%E5%8F%B3%E5%80%BC%E7%9A%84%E6%A6%82%E5%BF%B5"><span class="nav-text">左值和右值的概念</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%B7%A6%E5%80%BC%E5%BC%95%E7%94%A8%E5%92%8C%E5%8F%B3%E5%80%BC%E5%BC%95%E7%94%A8"><span class="nav-text">左值引用和右值引用</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%B7%A6%E5%80%BC%E5%BC%95%E7%94%A8"><span class="nav-text">左值引用</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8F%B3%E5%80%BC%E5%BC%95%E7%94%A8-1"><span class="nav-text">右值引用</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E7%A7%BB%E5%8A%A8%E8%AF%AD%E4%B9%89"><span class="nav-text">移动语义</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%B8%BA%E4%BB%80%E4%B9%88%E9%9C%80%E8%A6%81%E7%A7%BB%E5%8A%A8%E8%AF%AD%E4%B9%89"><span class="nav-text">为什么需要移动语义</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%BD%AC%E7%A7%BB%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0"><span class="nav-text">转移构造函数</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%BD%AC%E7%A7%BB%E8%B5%8B%E5%80%BC%E5%87%BD%E6%95%B0"><span class="nav-text">转移赋值函数</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#std-move"><span class="nav-text">std::move</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%AE%8C%E7%BE%8E%E8%BD%AC%E5%8F%91"><span class="nav-text">完美转发</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2"><span class="nav-text">类型转换</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#const-cast"><span class="nav-text">const_cast</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#reinterpret-cast"><span class="nav-text">reinterpret_cast</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#dynamic-cast"><span class="nav-text">dynamic_cast</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%B8%8A%E8%A1%8C%E8%BD%AC%E6%8D%A2%E5%92%8C%E4%B8%8B%E8%A1%8C%E8%BD%AC%E6%8D%A2"><span class="nav-text">上行转换和下行转换</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#static-cast"><span class="nav-text">static_cast</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#lambda%E8%A1%A8%E8%BE%BE%E5%BC%8F"><span class="nav-text">lambda表达式</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#std-function"><span class="nav-text">std::function</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%A6%82%E8%BF%B0"><span class="nav-text">概述</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#std-function%E7%9A%84%E5%88%9B%E5%BB%BA%E5%92%8C%E8%B0%83%E7%94%A8"><span class="nav-text">std::function的创建和调用</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%A9%BAstd-function"><span class="nav-text">空std::function</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#std-function%E4%B8%8E%E5%A4%9A%E6%80%81"><span class="nav-text">std::function与多态</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#std-function%E4%B8%8E%E9%9D%9E%E9%9D%99%E6%80%81%E6%88%90%E5%91%98%E5%87%BD%E6%95%B0"><span class="nav-text">std::function与非静态成员函数</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#std-function%E7%9A%84%E6%88%90%E5%91%98%E5%87%BD%E6%95%B0"><span class="nav-text">std::function的成员函数</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#std-bind"><span class="nav-text">std::bind</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%A6%82%E8%BF%B0-1"><span class="nav-text">概述</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%BB%91%E5%AE%9A%E8%87%AA%E7%94%B1%E5%87%BD%E6%95%B0"><span class="nav-text">绑定自由函数</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%BB%91%E5%AE%9A%E6%88%90%E5%91%98%E5%87%BD%E6%95%B0"><span class="nav-text">绑定成员函数</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8D%A0%E4%BD%8D%E7%AC%A6"><span class="nav-text">占位符</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%BB%91%E5%AE%9A%E5%88%B0lambda%E5%87%BD%E6%95%B0"><span class="nav-text">绑定到lambda函数</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#std-bind%E5%92%8Cstd-function%E7%BB%93%E5%90%88%E4%BD%BF%E7%94%A8"><span class="nav-text">std::bind和std::function结合使用</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E7%BB%A7%E6%89%BF%E6%9E%84%E9%80%A0"><span class="nav-text">继承构造</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%A7%94%E6%89%98%E6%9E%84%E9%80%A0"><span class="nav-text">委托构造</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E6%99%BA%E8%83%BD%E6%8C%87%E9%92%88"><span class="nav-text">智能指针</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%99%BA%E8%83%BD%E6%8C%87%E9%92%88%E7%9A%84%E6%A6%82%E8%BF%B0"><span class="nav-text">智能指针的概述</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#unique-ptr%EF%BC%88%E7%8B%AC%E5%8D%A0%E6%8C%87%E9%92%88%EF%BC%89"><span class="nav-text">unique_ptr（独占指针）</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%A6%82%E5%BF%B5%E5%92%8C%E7%94%A8%E6%B3%95"><span class="nav-text">概念和用法</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E9%94%99%E8%AF%AF%E4%BD%BF%E7%94%A8%E7%A4%BA%E4%BE%8B"><span class="nav-text">错误使用示例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%88%90%E5%91%98%E5%87%BD%E6%95%B0%E8%AF%A6%E8%A7%A3"><span class="nav-text">成员函数详解</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BD%BF%E7%94%A8make-unique%E5%88%9B%E5%BB%BA%E5%92%8C%E5%88%9D%E5%A7%8B%E5%8C%96"><span class="nav-text">使用make_unique创建和初始化</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#shared-ptr%EF%BC%88%E5%85%B1%E4%BA%AB%E6%8C%87%E9%92%88%EF%BC%89"><span class="nav-text">shared_ptr（共享指针）</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%A6%82%E5%BF%B5%E5%92%8C%E7%94%A8%E6%B3%95-1"><span class="nav-text">概念和用法</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E9%94%99%E8%AF%AF%E4%BD%BF%E7%94%A8%E7%A4%BA%E4%BE%8B-1"><span class="nav-text">错误使用示例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%88%90%E5%91%98%E5%87%BD%E6%95%B0%E8%AF%A6%E8%A7%A3-1"><span class="nav-text">成员函数详解</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BD%BF%E7%94%A8make-shared%E5%88%9B%E5%BB%BA%E5%92%8C%E5%88%9D%E5%A7%8B%E5%8C%96"><span class="nav-text">使用make_shared创建和初始化</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#enable-shared-from-this"><span class="nav-text">enable_shared_from_this</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#weak-ptr"><span class="nav-text">weak_ptr</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%A6%82%E5%BF%B5%E5%92%8C%E7%94%A8%E6%B3%95-2"><span class="nav-text">概念和用法</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%88%90%E5%91%98%E5%87%BD%E6%95%B0%E8%AF%A6%E8%A7%A3-2"><span class="nav-text">成员函数详解</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%9B%B8%E5%85%B3%E7%B1%BB%E5%92%8C%E5%85%A8%E5%B1%80%E5%87%BD%E6%95%B0"><span class="nav-text">相关类和全局函数</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#final%E5%85%B3%E9%94%AE%E5%AD%97"><span class="nav-text">final关键字</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#override%E5%85%B3%E9%94%AE%E5%AD%97"><span class="nav-text">override关键字</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#inline%E5%85%B3%E9%94%AE%E5%AD%97%EF%BC%88%E5%86%85%E8%81%94%E5%87%BD%E6%95%B0%EF%BC%89"><span class="nav-text">inline关键字（内联函数）</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#noexcept%E5%85%B3%E9%94%AE%E5%AD%97"><span class="nav-text">noexcept关键字</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#default%E5%85%B3%E9%94%AE%E5%AD%97"><span class="nav-text">default关键字</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#delete%E7%A6%81%E7%94%A8%E5%87%BD%E6%95%B0"><span class="nav-text">&#x3D;delete禁用函数</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%BD%BF%E7%94%A8using%E5%8F%96%E5%88%AB%E5%90%8D"><span class="nav-text">使用using取别名</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%87%BD%E6%95%B0%E6%A8%A1%E6%9D%BF%E7%9A%84%E9%BB%98%E8%AE%A4%E6%A8%A1%E6%9D%BF%E5%8F%82%E6%95%B0"><span class="nav-text">函数模板的默认模板参数</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%8F%AF%E5%8F%98%E5%8F%82%E6%95%B0%E6%A8%A1%E6%9D%BF"><span class="nav-text">可变参数模板</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8F%AF%E5%8F%98%E5%8F%82%E6%95%B0%E5%87%BD%E6%95%B0%E6%A8%A1%E6%9D%BF"><span class="nav-text">可变参数函数模板</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8F%AF%E5%8F%98%E5%8F%82%E6%95%B0%E7%B1%BB%E6%A8%A1%E6%9D%BF"><span class="nav-text">可变参数类模板</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%8E%B7%E5%8F%96%E5%8F%AF%E5%8F%98%E5%8F%82%E6%95%B0%E6%A8%A1%E6%9D%BF%E7%9A%84%E5%8F%82%E6%95%B0%E4%B8%AA%E6%95%B0"><span class="nav-text">获取可变参数模板的参数个数</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%A8%A1%E6%9D%BF%E7%89%B9%E5%8C%96"><span class="nav-text">模板特化</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%87%BD%E6%95%B0%E6%A8%A1%E6%9D%BF%E5%8F%82%E6%95%B0%E5%8C%85%E7%9A%84%E5%B1%95%E5%BC%80"><span class="nav-text">函数模板参数包的展开</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E9%80%92%E5%BD%92%E5%92%8C%E6%A8%A1%E6%9D%BF%E7%89%B9%E5%8C%96%E5%B1%95%E5%BC%80"><span class="nav-text">递归和模板特化展开</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E9%80%92%E5%BD%92%E3%80%81%E9%80%97%E5%8F%B7%E5%92%8C%E5%88%9D%E5%A7%8B%E5%8C%96%E5%88%97%E8%A1%A8%E5%B1%95%E5%BC%80"><span class="nav-text">递归、逗号和初始化列表展开</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%8A%98%E5%8F%A0%E8%A1%A8%E8%BE%BE%E5%BC%8F%EF%BC%88C-17%E8%B5%B7%EF%BC%89%E5%B1%95%E5%BC%80"><span class="nav-text">折叠表达式（C++17起）展开</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%B1%BB%E6%A8%A1%E6%9D%BF%E5%8F%82%E6%95%B0%E5%8C%85%E7%9A%84%E5%B1%95%E5%BC%80"><span class="nav-text">类模板参数包的展开</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%BB%A7%E6%89%BF%E6%96%B9%E5%BC%8F%E5%B1%95%E5%BC%80"><span class="nav-text">继承方式展开</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E9%80%92%E5%BD%92%E5%92%8C%E7%89%B9%E4%BE%8B%E5%8C%96%E5%B1%95%E5%BC%80"><span class="nav-text">递归和特例化展开</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%8A%98%E5%8F%A0%E8%A1%A8%E8%BE%BE%E5%BC%8F%EF%BC%88C-17%E8%B5%B7%EF%BC%89%E5%B1%95%E5%BC%80-1"><span class="nav-text">折叠表达式（C++17起）展开</span></a></li></ol></li></ol></li></ol>

    </div>
</div>
        </div>
    
</div>



                

            </div>

            

        </div>

        <div class="main-content-footer">
            <footer class="footer mt-5 py-5 h-auto text-base text-third-text-color relative border-t-2 border-t-border-color">
    <div class="info-container py-3 text-center">
        
            <div class="customize-info my-1">死亡是涅灭,抑或是永恒?</div>
        
        <div class="text-center">
            &copy;
            
              <span>2023</span>
              -
            
            2023&nbsp;&nbsp;<i class="fa-solid fa-heart fa-beat" style="--fa-animation-duration: 0.5s; color: #f54545"></i>&nbsp;&nbsp;<a href="/">雲之残骸</a>
        </div>
        
        <div class="relative text-center lg:absolute lg:left-[20px] lg:top-1/2 lg:-translate-y-1/2 lg:text-left">
            <span class="lg:block text-sm">由 <?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="relative top-[2px] inline-block align-baseline" version="1.1" id="圖層_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="1rem" height="1rem" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve"><path fill="#0E83CD" d="M256.4,25.8l-200,115.5L56,371.5l199.6,114.7l200-115.5l0.4-230.2L256.4,25.8z M349,354.6l-18.4,10.7l-18.6-11V275H200v79.6l-18.4,10.7l-18.6-11v-197l18.5-10.6l18.5,10.8V237h112v-79.6l18.5-10.6l18.5,10.8V354.6z"/></svg><a target="_blank" class="text-base" href="https://hexo.io">Hexo</a> 驱动</span>
            <span class="text-sm lg:block">主题&nbsp;<a class="text-base" target="_blank" href="https://github.com/EvanNotFound/hexo-theme-redefine">Redefine v2.4.4</a></span>
        </div>
        
        
            <div>
                博客已运行 <span class="odometer" id="runtime_days" ></span> 天 <span class="odometer" id="runtime_hours"></span> 小时 <span class="odometer" id="runtime_minutes"></span> 分钟 <span class="odometer" id="runtime_seconds"></span> 秒
            </div>
        
        
            <script data-swup-reload-script>
                try {
                    function odometer_init() {
                    const elements = document.querySelectorAll('.odometer');
                    elements.forEach(el => {
                        new Odometer({
                            el,
                            format: '( ddd).dd',
                            duration: 200
                        });
                    });
                    }
                    odometer_init();
                } catch (error) {}
            </script>
        
        
        
    </div>  
</footer>
        </div>
    </div>

    
        <div class="post-tools">
            <div class="post-tools-container">
    <ul class="article-tools-list">
        <!-- TOC aside toggle -->
        
            <li class="right-bottom-tools page-aside-toggle">
                <i class="fa-regular fa-outdent"></i>
            </li>
        

        <!-- go comment -->
        
    </ul>
</div>

        </div>
    

    <div class="right-side-tools-container">
        <div class="side-tools-container">
    <ul class="hidden-tools-list">
        <li class="right-bottom-tools tool-font-adjust-plus flex justify-center items-center">
            <i class="fa-regular fa-magnifying-glass-plus"></i>
        </li>

        <li class="right-bottom-tools tool-font-adjust-minus flex justify-center items-center">
            <i class="fa-regular fa-magnifying-glass-minus"></i>
        </li>

        <li class="right-bottom-tools tool-expand-width flex justify-center items-center">
            <i class="fa-regular fa-expand"></i>
        </li>

        <li class="right-bottom-tools tool-dark-light-toggle flex justify-center items-center">
            <i class="fa-regular fa-moon"></i>
        </li>

        <!-- rss -->
        

        

        <li class="right-bottom-tools tool-scroll-to-bottom flex justify-center items-center">
            <i class="fa-regular fa-arrow-down"></i>
        </li>
    </ul>

    <ul class="visible-tools-list">
        <li class="right-bottom-tools toggle-tools-list flex justify-center items-center">
            <i class="fa-regular fa-cog fa-spin"></i>
        </li>
        
            <li class="right-bottom-tools tool-scroll-to-top flex justify-center items-center">
                <i class="arrow-up fas fa-arrow-up"></i>
                <span class="percent"></span>
            </li>
        
        
    </ul>
</div>

    </div>

    <div class="image-viewer-container">
    <img src="">
</div>


    
        <div class="search-pop-overlay">
    <div class="popup search-popup">
        <div class="search-header">
          <span class="search-input-field-pre">
            <i class="fa-solid fa-keyboard"></i>
          </span>
            <div class="search-input-container">
                <input autocomplete="off"
                       autocorrect="off"
                       autocapitalize="off"
                       placeholder="搜索..."
                       spellcheck="false"
                       type="search"
                       class="search-input"
                >
            </div>
            <span class="popup-btn-close">
                <i class="fa-solid fa-times"></i>
            </span>
        </div>
        <div id="search-result">
            <div id="no-result">
                <i class="fa-solid fa-spinner fa-spin-pulse fa-5x fa-fw"></i>
            </div>
        </div>
    </div>
</div>

    

</main>


    
<script src="/js/libs/Swup.min.js"></script>

<script src="/js/libs/SwupSlideTheme.min.js"></script>

<script src="/js/libs/SwupScriptsPlugin.min.js"></script>

<script src="/js/libs/SwupProgressPlugin.min.js"></script>

<script src="/js/libs/SwupScrollPlugin.min.js"></script>

<script>
    const swup = new Swup({
        plugins: [
            new SwupScriptsPlugin({
                optin: true,
            }),
            new SwupProgressPlugin(),
            new SwupScrollPlugin({
                offset: 80,
            }),
            new SwupSlideTheme({
                mainElement: ".main-content-body",
            }),
        ],
        containers: ["#swup"],
    });

    swup.hooks.on("page:view", () => {
        Global.refresh();
    });

    // if (document.readyState === "complete") {
    //
    // } else {
    //     document.addEventListener("DOMContentLoaded", () => init());
    // }
</script>






<script src="/js/utils.js" type="module"></script>

<script src="/js/main.js" type="module"></script>

<script src="/js/layouts/navbarShrink.js" type="module"></script>

<script src="/js/tools/scrollTopBottom.js" type="module"></script>

<script src="/js/tools/lightDarkSwitch.js" type="module"></script>

<script src="/js/layouts/categoryList.js" type="module"></script>



    
<script src="/js/tools/localSearch.js"></script>






    
<script src="/js/layouts/lazyload.js"></script>




    
<script src="/js/tools/runtime.js"></script>

    
<script src="/js/libs/odometer.min.js"></script>

    
<link rel="stylesheet" href="/assets/odometer-theme-minimal.css">




  
<script src="/js/libs/Typed.min.js"></script>

  
<script src="/js/plugins/typed.js"></script>




    
<script src="/js/libs/mermaid.min.js"></script>

    
<script src="/js/plugins/mermaid.js"></script>




    
<script src="/js/libs/minimasonry.min.js"></script>

    
<script src="/js/plugins/masonry.js" type="module"></script>




<div class="post-scripts" data-swup-reload-script>
    
        
<script src="/js/libs/anime.min.js"></script>

        
<script src="/js/tools/tocToggle.js" type="module"></script>

<script src="/js/layouts/toc.js" type="module"></script>

<script src="/js/plugins/tabs.js" type="module"></script>

    
</div>


</body>
</html>
